(function (exports, Laya) { 'use strict'; class MathUtils3D { constructor() { } static isZero(v) { return Math.abs(v) < MathUtils3D.zeroTolerance; } static nearEqual(n1, n2) { if (MathUtils3D.isZero(n1 - n2)) return true; return false; } static fastInvSqrt(value) { if (MathUtils3D.isZero(value)) return value; return 1.0 / Math.sqrt(value); } } MathUtils3D.zeroTolerance = 1e-6; MathUtils3D.MaxValue = 3.40282347e+38; MathUtils3D.MinValue = -3.40282347e+38; MathUtils3D.Deg2Rad = Math.PI / 180; class Vector2 { constructor(x = 0, y = 0) { this.x = x; this.y = y; } setValue(x, y) { this.x = x; this.y = y; } static scale(a, b, out) { out.x = a.x * b; out.y = a.y * b; } fromArray(array, offset = 0) { this.x = array[offset + 0]; this.y = array[offset + 1]; } cloneTo(destObject) { var destVector2 = destObject; destVector2.x = this.x; destVector2.y = this.y; } static dot(a, b) { return (a.x * b.x) + (a.y * b.y); } static normalize(s, out) { var x = s.x, y = s.y; var len = x * x + y * y; if (len > 0) { len = 1 / Math.sqrt(len); out.x = x * len; out.y = y * len; } } static scalarLength(a) { var x = a.x, y = a.y; return Math.sqrt(x * x + y * y); } clone() { var destVector2 = new Vector2(); this.cloneTo(destVector2); return destVector2; } forNativeElement(nativeElements = null) { if (nativeElements) { this.elements = nativeElements; this.elements[0] = this.x; this.elements[1] = this.y; } else { this.elements = new Float32Array([this.x, this.y]); } Vector2.rewriteNumProperty(this, "x", 0); Vector2.rewriteNumProperty(this, "y", 1); } static rewriteNumProperty(proto, name, index) { Object["defineProperty"](proto, name, { "get": function () { return this.elements[index]; }, "set": function (v) { this.elements[index] = v; } }); } } Vector2.ZERO = new Vector2(0.0, 0.0); Vector2.ONE = new Vector2(1.0, 1.0); class Vector4 { constructor(x = 0, y = 0, z = 0, w = 0) { this.x = x; this.y = y; this.z = z; this.w = w; } setValue(x, y, z, w) { this.x = x; this.y = y; this.z = z; this.w = w; } fromArray(array, offset = 0) { this.x = array[offset + 0]; this.y = array[offset + 1]; this.z = array[offset + 2]; this.w = array[offset + 3]; } cloneTo(destObject) { var destVector4 = destObject; destVector4.x = this.x; destVector4.y = this.y; destVector4.z = this.z; destVector4.w = this.w; } clone() { var destVector4 = new Vector4(); this.cloneTo(destVector4); return destVector4; } static lerp(a, b, t, out) { var ax = a.x, ay = a.y, az = a.z, aw = a.w; out.x = ax + t * (b.x - ax); out.y = ay + t * (b.y - ay); out.z = az + t * (b.z - az); out.w = aw + t * (b.w - aw); } static transformByM4x4(vector4, m4x4, out) { var vx = vector4.x; var vy = vector4.y; var vz = vector4.z; var vw = vector4.w; var me = m4x4.elements; out.x = vx * me[0] + vy * me[4] + vz * me[8] + vw * me[12]; out.y = vx * me[1] + vy * me[5] + vz * me[9] + vw * me[13]; out.z = vx * me[2] + vy * me[6] + vz * me[10] + vw * me[14]; out.w = vx * me[3] + vy * me[7] + vz * me[11] + vw * me[15]; } static equals(a, b) { return MathUtils3D.nearEqual(Math.abs(a.x), Math.abs(b.x)) && MathUtils3D.nearEqual(Math.abs(a.y), Math.abs(b.y)) && MathUtils3D.nearEqual(Math.abs(a.z), Math.abs(b.z)) && MathUtils3D.nearEqual(Math.abs(a.w), Math.abs(b.w)); } length() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); } lengthSquared() { return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; } static normalize(s, out) { var len = s.length(); if (len > 0) { var inverse = 1.0 / len; out.x = s.x * inverse; out.y = s.y * inverse; out.z = s.z * inverse; out.w = s.w * inverse; } } static add(a, b, out) { out.x = a.x + b.x; out.y = a.y + b.y; out.z = a.z + b.z; out.w = a.w + b.w; } static subtract(a, b, out) { out.x = a.x - b.x; out.y = a.y - b.y; out.z = a.z - b.z; out.w = a.w - b.w; } static multiply(a, b, out) { out.x = a.x * b.x; out.y = a.y * b.y; out.z = a.z * b.z; out.w = a.w * b.w; } static scale(a, b, out) { out.x = a.x * b; out.y = a.y * b; out.z = a.z * b; out.w = a.w * b; } static Clamp(value, min, max, out) { var x = value.x; var y = value.y; var z = value.z; var w = value.w; var mineX = min.x; var mineY = min.y; var mineZ = min.z; var mineW = min.w; var maxeX = max.x; var maxeY = max.y; var maxeZ = max.z; var maxeW = max.w; x = (x > maxeX) ? maxeX : x; x = (x < mineX) ? mineX : x; y = (y > maxeY) ? maxeY : y; y = (y < mineY) ? mineY : y; z = (z > maxeZ) ? maxeZ : z; z = (z < mineZ) ? mineZ : z; w = (w > maxeW) ? maxeW : w; w = (w < mineW) ? mineW : w; out.x = x; out.y = y; out.z = z; out.w = w; } static distanceSquared(value1, value2) { var x = value1.x - value2.x; var y = value1.y - value2.y; var z = value1.z - value2.z; var w = value1.w - value2.w; return (x * x) + (y * y) + (z * z) + (w * w); } static distance(value1, value2) { var x = value1.x - value2.x; var y = value1.y - value2.y; var z = value1.z - value2.z; var w = value1.w - value2.w; return Math.sqrt((x * x) + (y * y) + (z * z) + (w * w)); } static dot(a, b) { return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w); } static min(a, b, out) { out.x = Math.min(a.x, b.x); out.y = Math.min(a.y, b.y); out.z = Math.min(a.z, b.z); out.w = Math.min(a.w, b.w); } static max(a, b, out) { out.x = Math.max(a.x, b.x); out.y = Math.max(a.y, b.y); out.z = Math.max(a.z, b.z); out.w = Math.max(a.w, b.w); } forNativeElement(nativeElements = null) { if (nativeElements) { this.elements = nativeElements; this.elements[0] = this.x; this.elements[1] = this.y; this.elements[2] = this.z; this.elements[3] = this.w; } else { this.elements = new Float32Array([this.x, this.y, this.z, this.w]); } Vector2.rewriteNumProperty(this, "x", 0); Vector2.rewriteNumProperty(this, "y", 1); Vector2.rewriteNumProperty(this, "z", 2); Vector2.rewriteNumProperty(this, "w", 3); } } Vector4.ZERO = new Vector4(); Vector4.ONE = new Vector4(1.0, 1.0, 1.0, 1.0); Vector4.UnitX = new Vector4(1.0, 0.0, 0.0, 0.0); Vector4.UnitY = new Vector4(0.0, 1.0, 0.0, 0.0); Vector4.UnitZ = new Vector4(0.0, 0.0, 1.0, 0.0); Vector4.UnitW = new Vector4(0.0, 0.0, 0.0, 1.0); class Vector3 { constructor(x = 0, y = 0, z = 0, nativeElements = null) { this.x = x; this.y = y; this.z = z; } static distanceSquared(value1, value2) { var x = value1.x - value2.x; var y = value1.y - value2.y; var z = value1.z - value2.z; return (x * x) + (y * y) + (z * z); } static distance(value1, value2) { var x = value1.x - value2.x; var y = value1.y - value2.y; var z = value1.z - value2.z; return Math.sqrt((x * x) + (y * y) + (z * z)); } static min(a, b, out) { out.x = Math.min(a.x, b.x); out.y = Math.min(a.y, b.y); out.z = Math.min(a.z, b.z); } static max(a, b, out) { out.x = Math.max(a.x, b.x); out.y = Math.max(a.y, b.y); out.z = Math.max(a.z, b.z); } static transformQuat(source, rotation, out) { var x = source.x, y = source.y, z = source.z, qx = rotation.x, qy = rotation.y, qz = rotation.z, qw = rotation.w, ix = qw * x + qy * z - qz * y, iy = qw * y + qz * x - qx * z, iz = qw * z + qx * y - qy * x, iw = -qx * x - qy * y - qz * z; out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; } static scalarLength(a) { var x = a.x, y = a.y, z = a.z; return Math.sqrt(x * x + y * y + z * z); } static scalarLengthSquared(a) { var x = a.x, y = a.y, z = a.z; return x * x + y * y + z * z; } static normalize(s, out) { var x = s.x, y = s.y, z = s.z; var len = x * x + y * y + z * z; if (len > 0) { len = 1 / Math.sqrt(len); out.x = x * len; out.y = y * len; out.z = z * len; } } static multiply(a, b, out) { out.x = a.x * b.x; out.y = a.y * b.y; out.z = a.z * b.z; } static scale(a, b, out) { out.x = a.x * b; out.y = a.y * b; out.z = a.z * b; } static lerp(a, b, t, out) { var ax = a.x, ay = a.y, az = a.z; out.x = ax + t * (b.x - ax); out.y = ay + t * (b.y - ay); out.z = az + t * (b.z - az); } static transformV3ToV3(vector, transform, result) { var intermediate = Vector3._tempVector4; Vector3.transformV3ToV4(vector, transform, intermediate); result.x = intermediate.x; result.y = intermediate.y; result.z = intermediate.z; } static transformV3ToV4(vector, transform, result) { var vectorX = vector.x; var vectorY = vector.y; var vectorZ = vector.z; var transformElem = transform.elements; result.x = (vectorX * transformElem[0]) + (vectorY * transformElem[4]) + (vectorZ * transformElem[8]) + transformElem[12]; result.y = (vectorX * transformElem[1]) + (vectorY * transformElem[5]) + (vectorZ * transformElem[9]) + transformElem[13]; result.z = (vectorX * transformElem[2]) + (vectorY * transformElem[6]) + (vectorZ * transformElem[10]) + transformElem[14]; result.w = (vectorX * transformElem[3]) + (vectorY * transformElem[7]) + (vectorZ * transformElem[11]) + transformElem[15]; } static TransformNormal(normal, transform, result) { var normalX = normal.x; var normalY = normal.y; var normalZ = normal.z; var transformElem = transform.elements; result.x = (normalX * transformElem[0]) + (normalY * transformElem[4]) + (normalZ * transformElem[8]); result.y = (normalX * transformElem[1]) + (normalY * transformElem[5]) + (normalZ * transformElem[9]); result.z = (normalX * transformElem[2]) + (normalY * transformElem[6]) + (normalZ * transformElem[10]); } static transformCoordinate(coordinate, transform, result) { var coordinateX = coordinate.x; var coordinateY = coordinate.y; var coordinateZ = coordinate.z; var transformElem = transform.elements; var w = coordinateX * transformElem[3] + coordinateY * transformElem[7] + coordinateZ * transformElem[11] + transformElem[15]; result.x = (coordinateX * transformElem[0] + coordinateY * transformElem[4] + coordinateZ * transformElem[8] + transformElem[12]) / w; result.y = (coordinateX * transformElem[1] + coordinateY * transformElem[5] + coordinateZ * transformElem[9] + transformElem[13]) / w; result.z = (coordinateX * transformElem[2] + coordinateY * transformElem[6] + coordinateZ * transformElem[10] + transformElem[14]) / w; } static Clamp(value, min, max, out) { var x = value.x; var y = value.y; var z = value.z; var mineX = min.x; var mineY = min.y; var mineZ = min.z; var maxeX = max.x; var maxeY = max.y; var maxeZ = max.z; x = (x > maxeX) ? maxeX : x; x = (x < mineX) ? mineX : x; y = (y > maxeY) ? maxeY : y; y = (y < mineY) ? mineY : y; z = (z > maxeZ) ? maxeZ : z; z = (z < mineZ) ? mineZ : z; out.x = x; out.y = y; out.z = z; } static add(a, b, out) { out.x = a.x + b.x; out.y = a.y + b.y; out.z = a.z + b.z; } static subtract(a, b, o) { o.x = a.x - b.x; o.y = a.y - b.y; o.z = a.z - b.z; } static cross(a, b, o) { var ax = a.x, ay = a.y, az = a.z, bx = b.x, by = b.y, bz = b.z; o.x = ay * bz - az * by; o.y = az * bx - ax * bz; o.z = ax * by - ay * bx; } static dot(a, b) { return (a.x * b.x) + (a.y * b.y) + (a.z * b.z); } static equals(a, b) { return MathUtils3D.nearEqual(a.x, b.x) && MathUtils3D.nearEqual(a.y, b.y) && MathUtils3D.nearEqual(a.z, b.z); } setValue(x, y, z) { this.x = x; this.y = y; this.z = z; } fromArray(array, offset = 0) { this.x = array[offset + 0]; this.y = array[offset + 1]; this.z = array[offset + 2]; } cloneTo(destObject) { var destVector3 = destObject; destVector3.x = this.x; destVector3.y = this.y; destVector3.z = this.z; } clone() { var destVector3 = new Vector3(); this.cloneTo(destVector3); return destVector3; } toDefault() { this.x = 0; this.y = 0; this.z = 0; } forNativeElement(nativeElements = null) { if (nativeElements) { this.elements = nativeElements; this.elements[0] = this.x; this.elements[1] = this.y; this.elements[2] = this.z; } else { this.elements = new Float32Array([this.x, this.y, this.z]); } Vector2.rewriteNumProperty(this, "x", 0); Vector2.rewriteNumProperty(this, "y", 1); Vector2.rewriteNumProperty(this, "z", 2); } } Vector3._tempVector4 = new Vector4(); Vector3._ZERO = new Vector3(0.0, 0.0, 0.0); Vector3._ONE = new Vector3(1.0, 1.0, 1.0); Vector3._NegativeUnitX = new Vector3(-1, 0, 0); Vector3._UnitX = new Vector3(1, 0, 0); Vector3._UnitY = new Vector3(0, 1, 0); Vector3._UnitZ = new Vector3(0, 0, 1); Vector3._ForwardRH = new Vector3(0, 0, -1); Vector3._ForwardLH = new Vector3(0, 0, 1); Vector3._Up = new Vector3(0, 1, 0); (function (PBRRenderQuality) { PBRRenderQuality[PBRRenderQuality["High"] = 0] = "High"; PBRRenderQuality[PBRRenderQuality["Low"] = 1] = "Low"; })(exports.PBRRenderQuality || (exports.PBRRenderQuality = {})); class Matrix3x3 { constructor() { var e = this.elements = new Float32Array(9); e[0] = 1; e[1] = 0; e[2] = 0; e[3] = 0; e[4] = 1; e[5] = 0; e[6] = 0; e[7] = 0; e[8] = 1; } static createRotationQuaternion(rotation, out) { var rotX = rotation.x; var rotY = rotation.y; var rotZ = rotation.z; var rotW = rotation.w; var xx = rotX * rotX; var yy = rotY * rotY; var zz = rotZ * rotZ; var xy = rotX * rotY; var zw = rotZ * rotW; var zx = rotZ * rotX; var yw = rotY * rotW; var yz = rotY * rotZ; var xw = rotX * rotW; var resultE = out.elements; resultE[0] = 1.0 - (2.0 * (yy + zz)); resultE[1] = 2.0 * (xy + zw); resultE[2] = 2.0 * (zx - yw); resultE[3] = 2.0 * (xy - zw); resultE[4] = 1.0 - (2.0 * (zz + xx)); resultE[5] = 2.0 * (yz + xw); resultE[6] = 2.0 * (zx + yw); resultE[7] = 2.0 * (yz - xw); resultE[8] = 1.0 - (2.0 * (yy + xx)); } static createFromTranslation(trans, out) { var e = out.elements; e[0] = 1; e[1] = 0; e[2] = 0; e[3] = 0; e[4] = 1; e[5] = 0; e[6] = trans.x; e[7] = trans.y; e[8] = 1; } static createFromRotation(rad, out) { var e = out.elements; var s = Math.sin(rad), c = Math.cos(rad); e[0] = c; e[1] = s; e[2] = 0; e[3] = -s; e[4] = c; e[5] = 0; e[6] = 0; e[7] = 0; e[8] = 1; } static createFromScaling(scale, out) { var e = out.elements; e[0] = scale.x; e[1] = 0; e[2] = 0; e[3] = 0; e[4] = scale.y; e[5] = 0; e[6] = 0; e[7] = 0; e[8] = scale.z; } static createFromMatrix4x4(sou, out) { var souE = sou.elements; var outE = out.elements; outE[0] = souE[0]; outE[1] = souE[1]; outE[2] = souE[2]; outE[3] = souE[4]; outE[4] = souE[5]; outE[5] = souE[6]; outE[6] = souE[8]; outE[7] = souE[9]; outE[8] = souE[10]; } static multiply(left, right, out) { var l = left.elements; var r = right.elements; var e = out.elements; var l11 = l[0], l12 = l[1], l13 = l[2]; var l21 = l[3], l22 = l[4], l23 = l[5]; var l31 = l[6], l32 = l[7], l33 = l[8]; var r11 = r[0], r12 = r[1], r13 = r[2]; var r21 = r[3], r22 = r[4], r23 = r[5]; var r31 = r[6], r32 = r[7], r33 = r[8]; e[0] = r11 * l11 + r12 * l21 + r13 * l31; e[1] = r11 * l12 + r12 * l22 + r13 * r32; e[2] = r11 * l13 + r12 * l23 + r13 * l33; e[3] = r21 * l11 + r22 * l21 + r23 * l31; e[4] = r21 * l12 + r22 * l22 + r23 * l32; e[5] = r21 * l13 + r22 * l23 + r23 * l33; e[6] = r31 * l11 + r32 * l21 + r33 * l31; e[7] = r31 * l12 + r32 * l22 + r33 * l32; e[8] = r31 * l13 + r32 * l23 + r33 * l33; } determinant() { var f = this.elements; var a00 = f[0], a01 = f[1], a02 = f[2]; var a10 = f[3], a11 = f[4], a12 = f[5]; var a20 = f[6], a21 = f[7], a22 = f[8]; return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); } translate(trans, out) { var e = out.elements; var f = this.elements; var a00 = f[0], a01 = f[1], a02 = f[2]; var a10 = f[3], a11 = f[4], a12 = f[5]; var a20 = f[6], a21 = f[7], a22 = f[8]; var x = trans.x, y = trans.y; e[0] = a00; e[1] = a01; e[2] = a02; e[3] = a10; e[4] = a11; e[5] = a12; e[6] = x * a00 + y * a10 + a20; e[7] = x * a01 + y * a11 + a21; e[8] = x * a02 + y * a12 + a22; } rotate(rad, out) { var e = out.elements; var f = this.elements; var a00 = f[0], a01 = f[1], a02 = f[2]; var a10 = f[3], a11 = f[4], a12 = f[5]; var a20 = f[6], a21 = f[7], a22 = f[8]; var s = Math.sin(rad); var c = Math.cos(rad); e[0] = c * a00 + s * a10; e[1] = c * a01 + s * a11; e[2] = c * a02 + s * a12; e[3] = c * a10 - s * a00; e[4] = c * a11 - s * a01; e[5] = c * a12 - s * a02; e[6] = a20; e[7] = a21; e[8] = a22; } scale(scale, out) { var e = out.elements; var f = this.elements; var x = scale.x, y = scale.y; e[0] = x * f[0]; e[1] = x * f[1]; e[2] = x * f[2]; e[3] = y * f[3]; e[4] = y * f[4]; e[5] = y * f[5]; e[6] = f[6]; e[7] = f[7]; e[8] = f[8]; } invert(out) { var e = out.elements; var f = this.elements; var a00 = f[0], a01 = f[1], a02 = f[2]; var a10 = f[3], a11 = f[4], a12 = f[5]; var a20 = f[6], a21 = f[7], a22 = f[8]; var b01 = a22 * a11 - a12 * a21; var b11 = -a22 * a10 + a12 * a20; var b21 = a21 * a10 - a11 * a20; var det = a00 * b01 + a01 * b11 + a02 * b21; if (!det) { out = null; } det = 1.0 / det; e[0] = b01 * det; e[1] = (-a22 * a01 + a02 * a21) * det; e[2] = (a12 * a01 - a02 * a11) * det; e[3] = b11 * det; e[4] = (a22 * a00 - a02 * a20) * det; e[5] = (-a12 * a00 + a02 * a10) * det; e[6] = b21 * det; e[7] = (-a21 * a00 + a01 * a20) * det; e[8] = (a11 * a00 - a01 * a10) * det; } transpose(out) { var e = out.elements; var f = this.elements; if (out === this) { var a01 = f[1], a02 = f[2], a12 = f[5]; e[1] = f[3]; e[2] = f[6]; e[3] = a01; e[5] = f[7]; e[6] = a02; e[7] = a12; } else { e[0] = f[0]; e[1] = f[3]; e[2] = f[6]; e[3] = f[1]; e[4] = f[4]; e[5] = f[7]; e[6] = f[2]; e[7] = f[5]; e[8] = f[8]; } } identity() { var e = this.elements; e[0] = 1; e[1] = 0; e[2] = 0; e[3] = 0; e[4] = 1; e[5] = 0; e[6] = 0; e[7] = 0; e[8] = 1; } cloneTo(destObject) { var i, s, d; s = this.elements; d = destObject.elements; if (s === d) { return; } for (i = 0; i < 9; ++i) { d[i] = s[i]; } } clone() { var dest = new Matrix3x3(); this.cloneTo(dest); return dest; } static lookAt(eye, target, up, out) { Vector3.subtract(eye, target, Matrix3x3._tempV30); Vector3.normalize(Matrix3x3._tempV30, Matrix3x3._tempV30); Vector3.cross(up, Matrix3x3._tempV30, Matrix3x3._tempV31); Vector3.normalize(Matrix3x3._tempV31, Matrix3x3._tempV31); Vector3.cross(Matrix3x3._tempV30, Matrix3x3._tempV31, Matrix3x3._tempV32); var v0 = Matrix3x3._tempV30; var v1 = Matrix3x3._tempV31; var v2 = Matrix3x3._tempV32; var me = out.elements; me[0] = v1.x; me[3] = v1.y; me[6] = v1.z; me[1] = v2.x; me[4] = v2.y; me[7] = v2.z; me[2] = v0.x; me[5] = v0.y; me[8] = v0.z; } } Matrix3x3.DEFAULT = new Matrix3x3(); Matrix3x3._tempV30 = new Vector3(); Matrix3x3._tempV31 = new Vector3(); Matrix3x3._tempV32 = new Vector3(); class ILaya3D { } ILaya3D.Shader3D = null; ILaya3D.Scene3D = null; ILaya3D.MeshRenderStaticBatchManager = null; ILaya3D.MeshRenderDynamicBatchManager = null; ILaya3D.SubMeshDynamicBatch = null; ILaya3D.Laya3D = null; ILaya3D.Matrix4x4 = null; ILaya3D.Physics3D = null; ILaya3D.ShadowLightType = null; class Quaternion { constructor(x = 0, y = 0, z = 0, w = 1, nativeElements = null) { this.x = x; this.y = y; this.z = z; this.w = w; } static createFromYawPitchRoll(yaw, pitch, roll, out) { var halfRoll = roll * 0.5; var halfPitch = pitch * 0.5; var halfYaw = yaw * 0.5; var sinRoll = Math.sin(halfRoll); var cosRoll = Math.cos(halfRoll); var sinPitch = Math.sin(halfPitch); var cosPitch = Math.cos(halfPitch); var sinYaw = Math.sin(halfYaw); var cosYaw = Math.cos(halfYaw); out.x = (cosYaw * sinPitch * cosRoll) + (sinYaw * cosPitch * sinRoll); out.y = (sinYaw * cosPitch * cosRoll) - (cosYaw * sinPitch * sinRoll); out.z = (cosYaw * cosPitch * sinRoll) - (sinYaw * sinPitch * cosRoll); out.w = (cosYaw * cosPitch * cosRoll) + (sinYaw * sinPitch * sinRoll); } static multiply(left, right, out) { var lx = left.x; var ly = left.y; var lz = left.z; var lw = left.w; var rx = right.x; var ry = right.y; var rz = right.z; var rw = right.w; var a = (ly * rz - lz * ry); var b = (lz * rx - lx * rz); var c = (lx * ry - ly * rx); var d = (lx * rx + ly * ry + lz * rz); out.x = (lx * rw + rx * lw) + a; out.y = (ly * rw + ry * lw) + b; out.z = (lz * rw + rz * lw) + c; out.w = lw * rw - d; } static arcTanAngle(x, y) { if (x == 0) { if (y == 1) return Math.PI / 2; return -Math.PI / 2; } if (x > 0) return Math.atan(y / x); if (x < 0) { if (y > 0) return Math.atan(y / x) + Math.PI; return Math.atan(y / x) - Math.PI; } return 0; } static angleTo(from, location, angle) { Vector3.subtract(location, from, Quaternion.TEMPVector30); Vector3.normalize(Quaternion.TEMPVector30, Quaternion.TEMPVector30); angle.x = Math.asin(Quaternion.TEMPVector30.y); angle.y = Quaternion.arcTanAngle(-Quaternion.TEMPVector30.z, -Quaternion.TEMPVector30.x); } static createFromAxisAngle(axis, rad, out) { rad = rad * 0.5; var s = Math.sin(rad); out.x = s * axis.x; out.y = s * axis.y; out.z = s * axis.z; out.w = Math.cos(rad); } static createFromMatrix4x4(mat, out) { var me = mat.elements; var sqrt; var half; var scale = me[0] + me[5] + me[10]; if (scale > 0.0) { sqrt = Math.sqrt(scale + 1.0); out.w = sqrt * 0.5; sqrt = 0.5 / sqrt; out.x = (me[6] - me[9]) * sqrt; out.y = (me[8] - me[2]) * sqrt; out.z = (me[1] - me[4]) * sqrt; } else if ((me[0] >= me[5]) && (me[0] >= me[10])) { sqrt = Math.sqrt(1.0 + me[0] - me[5] - me[10]); half = 0.5 / sqrt; out.x = 0.5 * sqrt; out.y = (me[1] + me[4]) * half; out.z = (me[2] + me[8]) * half; out.w = (me[6] - me[9]) * half; } else if (me[5] > me[10]) { sqrt = Math.sqrt(1.0 + me[5] - me[0] - me[10]); half = 0.5 / sqrt; out.x = (me[4] + me[1]) * half; out.y = 0.5 * sqrt; out.z = (me[9] + me[6]) * half; out.w = (me[8] - me[2]) * half; } else { sqrt = Math.sqrt(1.0 + me[10] - me[0] - me[5]); half = 0.5 / sqrt; out.x = (me[8] + me[2]) * half; out.y = (me[9] + me[6]) * half; out.z = 0.5 * sqrt; out.w = (me[1] - me[4]) * half; } } static slerp(left, right, t, out) { var ax = left.x, ay = left.y, az = left.z, aw = left.w, bx = right.x, by = right.y, bz = right.z, bw = right.w; var omega, cosom, sinom, scale0, scale1; cosom = ax * bx + ay * by + az * bz + aw * bw; if (cosom < 0.0) { cosom = -cosom; bx = -bx; by = -by; bz = -bz; bw = -bw; } if ((1.0 - cosom) > 0.000001) { omega = Math.acos(cosom); sinom = Math.sin(omega); scale0 = Math.sin((1.0 - t) * omega) / sinom; scale1 = Math.sin(t * omega) / sinom; } else { scale0 = 1.0 - t; scale1 = t; } out.x = scale0 * ax + scale1 * bx; out.y = scale0 * ay + scale1 * by; out.z = scale0 * az + scale1 * bz; out.w = scale0 * aw + scale1 * bw; return out; } static lerp(left, right, amount, out) { var inverse = 1.0 - amount; if (Quaternion.dot(left, right) >= 0) { out.x = (inverse * left.x) + (amount * right.x); out.y = (inverse * left.y) + (amount * right.y); out.z = (inverse * left.z) + (amount * right.z); out.w = (inverse * left.w) + (amount * right.w); } else { out.x = (inverse * left.x) - (amount * right.x); out.y = (inverse * left.y) - (amount * right.y); out.z = (inverse * left.z) - (amount * right.z); out.w = (inverse * left.w) - (amount * right.w); } out.normalize(out); } static add(left, right, out) { out.x = left.x + right.x; out.y = left.y + right.y; out.z = left.z + right.z; out.w = left.w + right.w; } static dot(left, right) { return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w; } scaling(scaling, out) { out.x = this.x * scaling; out.y = this.y * scaling; out.z = this.z * scaling; out.w = this.w * scaling; } normalize(out) { var len = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; if (len > 0) { len = 1 / Math.sqrt(len); out.x = this.x * len; out.y = this.y * len; out.z = this.z * len; out.w = this.w * len; } } length() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); } rotateX(rad, out) { rad *= 0.5; var bx = Math.sin(rad), bw = Math.cos(rad); out.x = this.x * bw + this.w * bx; out.y = this.y * bw + this.z * bx; out.z = this.z * bw - this.y * bx; out.w = this.w * bw - this.x * bx; } rotateY(rad, out) { rad *= 0.5; var by = Math.sin(rad), bw = Math.cos(rad); out.x = this.x * bw - this.z * by; out.y = this.y * bw + this.w * by; out.z = this.z * bw + this.x * by; out.w = this.w * bw - this.y * by; } rotateZ(rad, out) { rad *= 0.5; var bz = Math.sin(rad), bw = Math.cos(rad); out.x = this.x * bw + this.y * bz; out.y = this.y * bw - this.x * bz; out.z = this.z * bw + this.w * bz; out.w = this.w * bw - this.z * bz; } getYawPitchRoll(out) { Vector3.transformQuat(Vector3._ForwardRH, this, Quaternion.TEMPVector31); Vector3.transformQuat(Vector3._Up, this, Quaternion.TEMPVector32); var upe = Quaternion.TEMPVector32; Quaternion.angleTo(Vector3._ZERO, Quaternion.TEMPVector31, Quaternion.TEMPVector33); var angle = Quaternion.TEMPVector33; if (angle.x == Math.PI / 2) { angle.y = Quaternion.arcTanAngle(upe.z, upe.x); angle.z = 0; } else if (angle.x == -Math.PI / 2) { angle.y = Quaternion.arcTanAngle(-upe.z, -upe.x); angle.z = 0; } else { ILaya3D.Matrix4x4.createRotationY(-angle.y, ILaya3D.Matrix4x4.TEMPMatrix0); ILaya3D.Matrix4x4.createRotationX(-angle.x, ILaya3D.Matrix4x4.TEMPMatrix1); Vector3.transformCoordinate(Quaternion.TEMPVector32, ILaya3D.Matrix4x4.TEMPMatrix0, Quaternion.TEMPVector32); Vector3.transformCoordinate(Quaternion.TEMPVector32, ILaya3D.Matrix4x4.TEMPMatrix1, Quaternion.TEMPVector32); angle.z = Quaternion.arcTanAngle(upe.y, -upe.x); } if (angle.y <= -Math.PI) angle.y = Math.PI; if (angle.z <= -Math.PI) angle.z = Math.PI; if (angle.y >= Math.PI && angle.z >= Math.PI) { angle.y = 0; angle.z = 0; angle.x = Math.PI - angle.x; } var oe = out; oe.x = angle.y; oe.y = angle.x; oe.z = angle.z; } invert(out) { var a0 = this.x, a1 = this.y, a2 = this.z, a3 = this.w; var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3; var invDot = dot ? 1.0 / dot : 0; out.x = -a0 * invDot; out.y = -a1 * invDot; out.z = -a2 * invDot; out.w = a3 * invDot; } identity() { this.x = 0; this.y = 0; this.z = 0; this.w = 1; } fromArray(array, offset = 0) { this.x = array[offset + 0]; this.y = array[offset + 1]; this.z = array[offset + 2]; this.w = array[offset + 3]; } cloneTo(destObject) { if (this === destObject) { return; } destObject.x = this.x; destObject.y = this.y; destObject.z = this.z; destObject.w = this.w; } clone() { var dest = new Quaternion(); this.cloneTo(dest); return dest; } equals(b) { return MathUtils3D.nearEqual(this.x, b.x) && MathUtils3D.nearEqual(this.y, b.y) && MathUtils3D.nearEqual(this.z, b.z) && MathUtils3D.nearEqual(this.w, b.w); } static rotationLookAt(forward, up, out) { Quaternion.lookAt(Vector3._ZERO, forward, up, out); } static lookAt(eye, target, up, out) { Matrix3x3.lookAt(eye, target, up, Quaternion._tempMatrix3x3); Quaternion.rotationMatrix(Quaternion._tempMatrix3x3, out); } lengthSquared() { return (this.x * this.x) + (this.y * this.y) + (this.z * this.z) + (this.w * this.w); } static invert(value, out) { var lengthSq = value.lengthSquared(); if (!MathUtils3D.isZero(lengthSq)) { lengthSq = 1.0 / lengthSq; out.x = -value.x * lengthSq; out.y = -value.y * lengthSq; out.z = -value.z * lengthSq; out.w = value.w * lengthSq; } } static rotationMatrix(matrix3x3, out) { var me = matrix3x3.elements; var m11 = me[0]; var m12 = me[1]; var m13 = me[2]; var m21 = me[3]; var m22 = me[4]; var m23 = me[5]; var m31 = me[6]; var m32 = me[7]; var m33 = me[8]; var sqrt, half; var scale = m11 + m22 + m33; if (scale > 0) { sqrt = Math.sqrt(scale + 1); out.w = sqrt * 0.5; sqrt = 0.5 / sqrt; out.x = (m23 - m32) * sqrt; out.y = (m31 - m13) * sqrt; out.z = (m12 - m21) * sqrt; } else if ((m11 >= m22) && (m11 >= m33)) { sqrt = Math.sqrt(1 + m11 - m22 - m33); half = 0.5 / sqrt; out.x = 0.5 * sqrt; out.y = (m12 + m21) * half; out.z = (m13 + m31) * half; out.w = (m23 - m32) * half; } else if (m22 > m33) { sqrt = Math.sqrt(1 + m22 - m11 - m33); half = 0.5 / sqrt; out.x = (m21 + m12) * half; out.y = 0.5 * sqrt; out.z = (m32 + m23) * half; out.w = (m31 - m13) * half; } else { sqrt = Math.sqrt(1 + m33 - m11 - m22); half = 0.5 / sqrt; out.x = (m31 + m13) * half; out.y = (m32 + m23) * half; out.z = 0.5 * sqrt; out.w = (m12 - m21) * half; } } forNativeElement(nativeElements = null) { if (nativeElements) { this.elements = nativeElements; this.elements[0] = this.x; this.elements[1] = this.y; this.elements[2] = this.z; this.elements[3] = this.w; } else { this.elements = new Float32Array([this.x, this.y, this.z, this.w]); } Vector2.rewriteNumProperty(this, "x", 0); Vector2.rewriteNumProperty(this, "y", 1); Vector2.rewriteNumProperty(this, "z", 2); Vector2.rewriteNumProperty(this, "w", 3); } } Quaternion.TEMPVector30 = new Vector3(); Quaternion.TEMPVector31 = new Vector3(); Quaternion.TEMPVector32 = new Vector3(); Quaternion.TEMPVector33 = new Vector3(); Quaternion._tempMatrix3x3 = new Matrix3x3(); Quaternion.DEFAULT = new Quaternion(); Quaternion.NAN = new Quaternion(NaN, NaN, NaN, NaN); class Matrix4x4 { constructor(m11 = 1, m12 = 0, m13 = 0, m14 = 0, m21 = 0, m22 = 1, m23 = 0, m24 = 0, m31 = 0, m32 = 0, m33 = 1, m34 = 0, m41 = 0, m42 = 0, m43 = 0, m44 = 1, elements = null) { var e = elements ? this.elements = elements : this.elements = new Float32Array(16); e[0] = m11; e[1] = m12; e[2] = m13; e[3] = m14; e[4] = m21; e[5] = m22; e[6] = m23; e[7] = m24; e[8] = m31; e[9] = m32; e[10] = m33; e[11] = m34; e[12] = m41; e[13] = m42; e[14] = m43; e[15] = m44; } static createRotationX(rad, out) { var oe = out.elements; var s = Math.sin(rad), c = Math.cos(rad); oe[1] = oe[2] = oe[3] = oe[4] = oe[7] = oe[8] = oe[11] = oe[12] = oe[13] = oe[14] = 0; oe[0] = oe[15] = 1; oe[5] = oe[10] = c; oe[6] = s; oe[9] = -s; } static createRotationY(rad, out) { var oe = out.elements; var s = Math.sin(rad), c = Math.cos(rad); oe[1] = oe[3] = oe[4] = oe[6] = oe[7] = oe[9] = oe[11] = oe[12] = oe[13] = oe[14] = 0; oe[5] = oe[15] = 1; oe[0] = oe[10] = c; oe[2] = -s; oe[8] = s; } static createRotationZ(rad, out) { var oe = out.elements; var s = Math.sin(rad), c = Math.cos(rad); oe[2] = oe[3] = oe[6] = oe[7] = oe[8] = oe[9] = oe[11] = oe[12] = oe[13] = oe[14] = 0; oe[10] = oe[15] = 1; oe[0] = oe[5] = c; oe[1] = s; oe[4] = -s; } static createRotationYawPitchRoll(yaw, pitch, roll, result) { Quaternion.createFromYawPitchRoll(yaw, pitch, roll, Matrix4x4._tempQuaternion); Matrix4x4.createRotationQuaternion(Matrix4x4._tempQuaternion, result); } static createRotationAxis(axis, angle, result) { var x = axis.x; var y = axis.y; var z = axis.z; var cos = Math.cos(angle); var sin = Math.sin(angle); var xx = x * x; var yy = y * y; var zz = z * z; var xy = x * y; var xz = x * z; var yz = y * z; var resultE = result.elements; resultE[3] = resultE[7] = resultE[11] = resultE[12] = resultE[13] = resultE[14] = 0; resultE[15] = 1.0; resultE[0] = xx + (cos * (1.0 - xx)); resultE[1] = (xy - (cos * xy)) + (sin * z); resultE[2] = (xz - (cos * xz)) - (sin * y); resultE[4] = (xy - (cos * xy)) - (sin * z); resultE[5] = yy + (cos * (1.0 - yy)); resultE[6] = (yz - (cos * yz)) + (sin * x); resultE[8] = (xz - (cos * xz)) + (sin * y); resultE[9] = (yz - (cos * yz)) - (sin * x); resultE[10] = zz + (cos * (1.0 - zz)); } setRotation(rotation) { var rotationX = rotation.x; var rotationY = rotation.y; var rotationZ = rotation.z; var rotationW = rotation.w; var xx = rotationX * rotationX; var yy = rotationY * rotationY; var zz = rotationZ * rotationZ; var xy = rotationX * rotationY; var zw = rotationZ * rotationW; var zx = rotationZ * rotationX; var yw = rotationY * rotationW; var yz = rotationY * rotationZ; var xw = rotationX * rotationW; var e = this.elements; e[0] = 1.0 - (2.0 * (yy + zz)); e[1] = 2.0 * (xy + zw); e[2] = 2.0 * (zx - yw); e[4] = 2.0 * (xy - zw); e[5] = 1.0 - (2.0 * (zz + xx)); e[6] = 2.0 * (yz + xw); e[8] = 2.0 * (zx + yw); e[9] = 2.0 * (yz - xw); e[10] = 1.0 - (2.0 * (yy + xx)); } setPosition(position) { var e = this.elements; e[12] = position.x; e[13] = position.y; e[14] = position.z; } static createRotationQuaternion(rotation, result) { var resultE = result.elements; var rotationX = rotation.x; var rotationY = rotation.y; var rotationZ = rotation.z; var rotationW = rotation.w; var xx = rotationX * rotationX; var yy = rotationY * rotationY; var zz = rotationZ * rotationZ; var xy = rotationX * rotationY; var zw = rotationZ * rotationW; var zx = rotationZ * rotationX; var yw = rotationY * rotationW; var yz = rotationY * rotationZ; var xw = rotationX * rotationW; resultE[3] = resultE[7] = resultE[11] = resultE[12] = resultE[13] = resultE[14] = 0; resultE[15] = 1.0; resultE[0] = 1.0 - (2.0 * (yy + zz)); resultE[1] = 2.0 * (xy + zw); resultE[2] = 2.0 * (zx - yw); resultE[4] = 2.0 * (xy - zw); resultE[5] = 1.0 - (2.0 * (zz + xx)); resultE[6] = 2.0 * (yz + xw); resultE[8] = 2.0 * (zx + yw); resultE[9] = 2.0 * (yz - xw); resultE[10] = 1.0 - (2.0 * (yy + xx)); } static createTranslate(trans, out) { var oe = out.elements; oe[4] = oe[8] = oe[1] = oe[9] = oe[2] = oe[6] = oe[3] = oe[7] = oe[11] = 0; oe[0] = oe[5] = oe[10] = oe[15] = 1; oe[12] = trans.x; oe[13] = trans.y; oe[14] = trans.z; } static createScaling(scale, out) { var oe = out.elements; oe[0] = scale.x; oe[5] = scale.y; oe[10] = scale.z; oe[1] = oe[4] = oe[8] = oe[12] = oe[9] = oe[13] = oe[2] = oe[6] = oe[14] = oe[3] = oe[7] = oe[11] = 0; oe[15] = 1; } static multiply(left, right, out) { var l = right.elements; var r = left.elements; var e = out.elements; var l11 = l[0], l12 = l[1], l13 = l[2], l14 = l[3]; var l21 = l[4], l22 = l[5], l23 = l[6], l24 = l[7]; var l31 = l[8], l32 = l[9], l33 = l[10], l34 = l[11]; var l41 = l[12], l42 = l[13], l43 = l[14], l44 = l[15]; var r11 = r[0], r12 = r[1], r13 = r[2], r14 = r[3]; var r21 = r[4], r22 = r[5], r23 = r[6], r24 = r[7]; var r31 = r[8], r32 = r[9], r33 = r[10], r34 = r[11]; var r41 = r[12], r42 = r[13], r43 = r[14], r44 = r[15]; e[0] = (l11 * r11) + (l12 * r21) + (l13 * r31) + (l14 * r41); e[1] = (l11 * r12) + (l12 * r22) + (l13 * r32) + (l14 * r42); e[2] = (l11 * r13) + (l12 * r23) + (l13 * r33) + (l14 * r43); e[3] = (l11 * r14) + (l12 * r24) + (l13 * r34) + (l14 * r44); e[4] = (l21 * r11) + (l22 * r21) + (l23 * r31) + (l24 * r41); e[5] = (l21 * r12) + (l22 * r22) + (l23 * r32) + (l24 * r42); e[6] = (l21 * r13) + (l22 * r23) + (l23 * r33) + (l24 * r43); e[7] = (l21 * r14) + (l22 * r24) + (l23 * r34) + (l24 * r44); e[8] = (l31 * r11) + (l32 * r21) + (l33 * r31) + (l34 * r41); e[9] = (l31 * r12) + (l32 * r22) + (l33 * r32) + (l34 * r42); e[10] = (l31 * r13) + (l32 * r23) + (l33 * r33) + (l34 * r43); e[11] = (l31 * r14) + (l32 * r24) + (l33 * r34) + (l34 * r44); e[12] = (l41 * r11) + (l42 * r21) + (l43 * r31) + (l44 * r41); e[13] = (l41 * r12) + (l42 * r22) + (l43 * r32) + (l44 * r42); e[14] = (l41 * r13) + (l42 * r23) + (l43 * r33) + (l44 * r43); e[15] = (l41 * r14) + (l42 * r24) + (l43 * r34) + (l44 * r44); } static multiplyForNative(left, right, out) { Laya.LayaGL.instance.matrix4x4Multiply(left.elements, right.elements, out.elements); } static createFromQuaternion(rotation, out) { var e = out.elements; var x = rotation.x, y = rotation.y, z = rotation.z, w = rotation.w; var x2 = x + x; var y2 = y + y; var z2 = z + z; var xx = x * x2; var yx = y * x2; var yy = y * y2; var zx = z * x2; var zy = z * y2; var zz = z * z2; var wx = w * x2; var wy = w * y2; var wz = w * z2; e[0] = 1 - yy - zz; e[1] = yx + wz; e[2] = zx - wy; e[3] = 0; e[4] = yx - wz; e[5] = 1 - xx - zz; e[6] = zy + wx; e[7] = 0; e[8] = zx + wy; e[9] = zy - wx; e[10] = 1 - xx - yy; e[11] = 0; e[12] = 0; e[13] = 0; e[14] = 0; e[15] = 1; } static createAffineTransformation(trans, rot, scale, out) { var oe = out.elements; var x = rot.x, y = rot.y, z = rot.z, w = rot.w, x2 = x + x, y2 = y + y, z2 = z + z; var xx = x * x2, xy = x * y2, xz = x * z2, yy = y * y2, yz = y * z2, zz = z * z2; var wx = w * x2, wy = w * y2, wz = w * z2, sx = scale.x, sy = scale.y, sz = scale.z; oe[0] = (1 - (yy + zz)) * sx; oe[1] = (xy + wz) * sx; oe[2] = (xz - wy) * sx; oe[3] = 0; oe[4] = (xy - wz) * sy; oe[5] = (1 - (xx + zz)) * sy; oe[6] = (yz + wx) * sy; oe[7] = 0; oe[8] = (xz + wy) * sz; oe[9] = (yz - wx) * sz; oe[10] = (1 - (xx + yy)) * sz; oe[11] = 0; oe[12] = trans.x; oe[13] = trans.y; oe[14] = trans.z; oe[15] = 1; } static createLookAt(eye, target, up, out) { var oE = out.elements; var xaxis = Matrix4x4._tempVector0; var yaxis = Matrix4x4._tempVector1; var zaxis = Matrix4x4._tempVector2; Vector3.subtract(eye, target, zaxis); Vector3.normalize(zaxis, zaxis); Vector3.cross(up, zaxis, xaxis); Vector3.normalize(xaxis, xaxis); Vector3.cross(zaxis, xaxis, yaxis); oE[3] = oE[7] = oE[11] = 0; oE[15] = 1; oE[0] = xaxis.x; oE[4] = xaxis.y; oE[8] = xaxis.z; oE[1] = yaxis.x; oE[5] = yaxis.y; oE[9] = yaxis.z; oE[2] = zaxis.x; oE[6] = zaxis.y; oE[10] = zaxis.z; oE[12] = -Vector3.dot(xaxis, eye); oE[13] = -Vector3.dot(yaxis, eye); oE[14] = -Vector3.dot(zaxis, eye); } static createPerspective(fov, aspect, znear, zfar, out) { var yScale = 1.0 / Math.tan(fov * 0.5); var xScale = yScale / aspect; var halfWidth = znear / xScale; var halfHeight = znear / yScale; Matrix4x4.createPerspectiveOffCenter(-halfWidth, halfWidth, -halfHeight, halfHeight, znear, zfar, out); } static createPerspectiveOffCenter(left, right, bottom, top, znear, zfar, out) { var oe = out.elements; var zRange = zfar / (zfar - znear); oe[1] = oe[2] = oe[3] = oe[4] = oe[6] = oe[7] = oe[12] = oe[13] = oe[15] = 0; oe[0] = 2.0 * znear / (right - left); oe[5] = 2.0 * znear / (top - bottom); oe[8] = (left + right) / (right - left); oe[9] = (top + bottom) / (top - bottom); oe[10] = -zRange; oe[11] = -1.0; oe[14] = -znear * zRange; } static createOrthoOffCenter(left, right, bottom, top, znear, zfar, out) { var oe = out.elements; var zRange = 1.0 / (zfar - znear); oe[1] = oe[2] = oe[3] = oe[4] = oe[6] = oe[8] = oe[7] = oe[9] = oe[11] = 0; oe[15] = 1; oe[0] = 2.0 / (right - left); oe[5] = 2.0 / (top - bottom); oe[10] = -zRange; oe[12] = (left + right) / (left - right); oe[13] = (top + bottom) / (bottom - top); oe[14] = -znear * zRange; } getElementByRowColumn(row, column) { if (row < 0 || row > 3) throw new Error("row Rows and columns for matrices run from 0 to 3, inclusive."); if (column < 0 || column > 3) throw new Error("column Rows and columns for matrices run from 0 to 3, inclusive."); return this.elements[(row * 4) + column]; } setElementByRowColumn(row, column, value) { if (row < 0 || row > 3) throw new Error("row Rows and columns for matrices run from 0 to 3, inclusive."); if (column < 0 || column > 3) throw new Error("column Rows and columns for matrices run from 0 to 3, inclusive."); this.elements[(row * 4) + column] = value; } equalsOtherMatrix(other) { var e = this.elements; var oe = other.elements; return (MathUtils3D.nearEqual(e[0], oe[0]) && MathUtils3D.nearEqual(e[1], oe[1]) && MathUtils3D.nearEqual(e[2], oe[2]) && MathUtils3D.nearEqual(e[3], oe[3]) && MathUtils3D.nearEqual(e[4], oe[4]) && MathUtils3D.nearEqual(e[5], oe[5]) && MathUtils3D.nearEqual(e[6], oe[6]) && MathUtils3D.nearEqual(e[7], oe[7]) && MathUtils3D.nearEqual(e[8], oe[8]) && MathUtils3D.nearEqual(e[9], oe[9]) && MathUtils3D.nearEqual(e[10], oe[10]) && MathUtils3D.nearEqual(e[11], oe[11]) && MathUtils3D.nearEqual(e[12], oe[12]) && MathUtils3D.nearEqual(e[13], oe[13]) && MathUtils3D.nearEqual(e[14], oe[14]) && MathUtils3D.nearEqual(e[15], oe[15])); } decomposeTransRotScale(translation, rotation, scale) { var rotationMatrix = Matrix4x4._tempMatrix4x4; if (this.decomposeTransRotMatScale(translation, rotationMatrix, scale)) { Quaternion.createFromMatrix4x4(rotationMatrix, rotation); return true; } else { rotation.identity(); return false; } } decomposeTransRotMatScale(translation, rotationMatrix, scale) { var e = this.elements; var te = translation; var re = rotationMatrix.elements; var se = scale; te.x = e[12]; te.y = e[13]; te.z = e[14]; var m11 = e[0], m12 = e[1], m13 = e[2]; var m21 = e[4], m22 = e[5], m23 = e[6]; var m31 = e[8], m32 = e[9], m33 = e[10]; var sX = se.x = Math.sqrt((m11 * m11) + (m12 * m12) + (m13 * m13)); var sY = se.y = Math.sqrt((m21 * m21) + (m22 * m22) + (m23 * m23)); var sZ = se.z = Math.sqrt((m31 * m31) + (m32 * m32) + (m33 * m33)); if (MathUtils3D.isZero(sX) || MathUtils3D.isZero(sY) || MathUtils3D.isZero(sZ)) { re[1] = re[2] = re[3] = re[4] = re[6] = re[7] = re[8] = re[9] = re[11] = re[12] = re[13] = re[14] = 0; re[0] = re[5] = re[10] = re[15] = 1; return false; } var at = Matrix4x4._tempVector0; at.x = m31 / sZ; at.y = m32 / sZ; at.z = m33 / sZ; var tempRight = Matrix4x4._tempVector1; tempRight.x = m11 / sX; tempRight.y = m12 / sX; tempRight.z = m13 / sX; var up = Matrix4x4._tempVector2; Vector3.cross(at, tempRight, up); var right = Matrix4x4._tempVector1; Vector3.cross(up, at, right); re[3] = re[7] = re[11] = re[12] = re[13] = re[14] = 0; re[15] = 1; re[0] = right.x; re[1] = right.y; re[2] = right.z; re[4] = up.x; re[5] = up.y; re[6] = up.z; re[8] = at.x; re[9] = at.y; re[10] = at.z; ((re[0] * m11 + re[1] * m12 + re[2] * m13) < 0.0) && (se.x = -sX); ((re[4] * m21 + re[5] * m22 + re[6] * m23) < 0.0) && (se.y = -sY); ((re[8] * m31 + re[9] * m32 + re[10] * m33) < 0.0) && (se.z = -sZ); return true; } decomposeYawPitchRoll(yawPitchRoll) { var pitch = Math.asin(-this.elements[9]); yawPitchRoll.y = pitch; var test = Math.cos(pitch); if (test > MathUtils3D.zeroTolerance) { yawPitchRoll.z = Math.atan2(this.elements[1], this.elements[5]); yawPitchRoll.x = Math.atan2(this.elements[8], this.elements[10]); } else { yawPitchRoll.z = Math.atan2(-this.elements[4], this.elements[0]); yawPitchRoll.x = 0.0; } } normalize() { var v = this.elements; var c = v[0], d = v[1], e = v[2], g = Math.sqrt(c * c + d * d + e * e); if (g) { if (g == 1) return; } else { v[0] = 0; v[1] = 0; v[2] = 0; return; } g = 1 / g; v[0] = c * g; v[1] = d * g; v[2] = e * g; } transpose() { var e, t; e = this.elements; t = e[1]; e[1] = e[4]; e[4] = t; t = e[2]; e[2] = e[8]; e[8] = t; t = e[3]; e[3] = e[12]; e[12] = t; t = e[6]; e[6] = e[9]; e[9] = t; t = e[7]; e[7] = e[13]; e[13] = t; t = e[11]; e[11] = e[14]; e[14] = t; return this; } invert(out) { var ae = this.elements; var oe = out.elements; var a00 = ae[0], a01 = ae[1], a02 = ae[2], a03 = ae[3], a10 = ae[4], a11 = ae[5], a12 = ae[6], a13 = ae[7], a20 = ae[8], a21 = ae[9], a22 = ae[10], a23 = ae[11], a30 = ae[12], a31 = ae[13], a32 = ae[14], a33 = ae[15], b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10, b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12, b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30, b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32, det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; if (Math.abs(det) === 0.0) { return; } det = 1.0 / det; oe[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; oe[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; oe[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; oe[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; oe[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; oe[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; oe[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; oe[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; oe[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; oe[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; oe[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; oe[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; oe[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; oe[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; oe[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; oe[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; } static billboard(objectPosition, cameraPosition, cameraRight, cameraUp, cameraForward, mat) { Vector3.subtract(objectPosition, cameraPosition, Matrix4x4._tempVector0); var lengthSq = Vector3.scalarLengthSquared(Matrix4x4._tempVector0); if (MathUtils3D.isZero(lengthSq)) { Vector3.scale(cameraForward, -1, Matrix4x4._tempVector1); Matrix4x4._tempVector1.cloneTo(Matrix4x4._tempVector0); } else { Vector3.scale(Matrix4x4._tempVector0, 1 / Math.sqrt(lengthSq), Matrix4x4._tempVector0); } Vector3.cross(cameraUp, Matrix4x4._tempVector0, Matrix4x4._tempVector2); Vector3.normalize(Matrix4x4._tempVector2, Matrix4x4._tempVector2); Vector3.cross(Matrix4x4._tempVector0, Matrix4x4._tempVector2, Matrix4x4._tempVector3); var crosse = Matrix4x4._tempVector2; var finale = Matrix4x4._tempVector3; var diffee = Matrix4x4._tempVector0; var obpose = objectPosition; var mate = mat.elements; mate[0] = crosse.x; mate[1] = crosse.y; mate[2] = crosse.z; mate[3] = 0.0; mate[4] = finale.x; mate[5] = finale.y; mate[6] = finale.z; mate[7] = 0.0; mate[8] = diffee.x; mate[9] = diffee.y; mate[10] = diffee.z; mate[11] = 0.0; mate[12] = obpose.x; mate[13] = obpose.y; mate[14] = obpose.z; mate[15] = 1.0; } identity() { var e = this.elements; e[1] = e[2] = e[3] = e[4] = e[6] = e[7] = e[8] = e[9] = e[11] = e[12] = e[13] = e[14] = 0; e[0] = e[5] = e[10] = e[15] = 1; } cloneTo(destObject) { var i, s, d; s = this.elements; d = destObject.elements; if (s === d) { return; } for (i = 0; i < 16; ++i) { d[i] = s[i]; } } clone() { var dest = new Matrix4x4(); this.cloneTo(dest); return dest; } static translation(v3, out) { var oe = out.elements; oe[0] = oe[5] = oe[10] = oe[15] = 1; oe[12] = v3.x; oe[13] = v3.y; oe[14] = v3.z; } getTranslationVector(out) { var me = this.elements; out.x = me[12]; out.y = me[13]; out.z = me[14]; } setTranslationVector(translate) { var me = this.elements; var ve = translate; me[12] = ve.x; me[13] = ve.y; me[14] = ve.z; } getForward(out) { var me = this.elements; out.x = -me[8]; out.y = -me[9]; out.z = -me[10]; } setForward(forward) { var me = this.elements; me[8] = -forward.x; me[9] = -forward.y; me[10] = -forward.z; } } Matrix4x4._tempMatrix4x4 = new Matrix4x4(); Matrix4x4.TEMPMatrix0 = new Matrix4x4(); Matrix4x4.TEMPMatrix1 = new Matrix4x4(); Matrix4x4._tempVector0 = new Vector3(); Matrix4x4._tempVector1 = new Vector3(); Matrix4x4._tempVector2 = new Vector3(); Matrix4x4._tempVector3 = new Vector3(); Matrix4x4._tempQuaternion = new Quaternion(); Matrix4x4.DEFAULT = new Matrix4x4(); Matrix4x4.ZERO = new Matrix4x4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); class ColliderShape { constructor() { this._scale = new Vector3(1, 1, 1); this._centerMatrix = new Matrix4x4(); this._attatched = false; this._indexInCompound = -1; this._compoundParent = null; this._attatchedCollisionObject = null; this._referenceCount = 0; this._localOffset = new Vector3(0, 0, 0); this._localRotation = new Quaternion(0, 0, 0, 1); this.needsCustomCollisionCallback = false; } static __init__() { var bt = ILaya3D.Physics3D._bullet; ColliderShape._btScale = bt.btVector3_create(1, 1, 1); ColliderShape._btVector30 = bt.btVector3_create(0, 0, 0); ColliderShape._btQuaternion0 = bt.btQuaternion_create(0, 0, 0, 1); ColliderShape._btTransform0 = bt.btTransform_create(); } static _createAffineTransformation(trans, rot, outE) { var x = rot.x, y = rot.y, z = rot.z, w = rot.w, x2 = x + x, y2 = y + y, z2 = z + z; var xx = x * x2, xy = x * y2, xz = x * z2, yy = y * y2, yz = y * z2, zz = z * z2; var wx = w * x2, wy = w * y2, wz = w * z2; outE[0] = (1 - (yy + zz)); outE[1] = (xy + wz); outE[2] = (xz - wy); outE[3] = 0; outE[4] = (xy - wz); outE[5] = (1 - (xx + zz)); outE[6] = (yz + wx); outE[7] = 0; outE[8] = (xz + wy); outE[9] = (yz - wx); outE[10] = (1 - (xx + yy)); outE[11] = 0; outE[12] = trans.x; outE[13] = trans.y; outE[14] = trans.z; outE[15] = 1; } get type() { return this._type; } get localOffset() { return this._localOffset; } set localOffset(value) { this._localOffset = value; if (this._compoundParent) this._compoundParent._updateChildTransform(this); } get localRotation() { return this._localRotation; } set localRotation(value) { this._localRotation = value; if (this._compoundParent) this._compoundParent._updateChildTransform(this); } _setScale(value) { if (this._compoundParent) { this.updateLocalTransformations(); } else { var bt = ILaya3D.Physics3D._bullet; bt.btVector3_setValue(ColliderShape._btScale, value.x, value.y, value.z); bt.btCollisionShape_setLocalScaling(this._btShape, ColliderShape._btScale); } } _addReference() { this._referenceCount++; } _removeReference() { this._referenceCount--; } updateLocalTransformations() { if (this._compoundParent) { var offset = ColliderShape._tempVector30; Vector3.multiply(this.localOffset, this._scale, offset); ColliderShape._createAffineTransformation(offset, this.localRotation, this._centerMatrix.elements); } else { ColliderShape._createAffineTransformation(this.localOffset, this.localRotation, this._centerMatrix.elements); } } cloneTo(destObject) { var destColliderShape = destObject; this._localOffset.cloneTo(destColliderShape.localOffset); this._localRotation.cloneTo(destColliderShape.localRotation); destColliderShape.localOffset = destColliderShape.localOffset; destColliderShape.localRotation = destColliderShape.localRotation; } clone() { return null; } destroy() { if (this._btShape) { ILaya3D.Physics3D._bullet.btCollisionShape_destroy(this._btShape); this._btShape = null; } } } ColliderShape.SHAPEORIENTATION_UPX = 0; ColliderShape.SHAPEORIENTATION_UPY = 1; ColliderShape.SHAPEORIENTATION_UPZ = 2; ColliderShape.SHAPETYPES_BOX = 0; ColliderShape.SHAPETYPES_SPHERE = 1; ColliderShape.SHAPETYPES_CYLINDER = 2; ColliderShape.SHAPETYPES_CAPSULE = 3; ColliderShape.SHAPETYPES_CONVEXHULL = 4; ColliderShape.SHAPETYPES_COMPOUND = 5; ColliderShape.SHAPETYPES_STATICPLANE = 6; ColliderShape.SHAPETYPES_CONE = 7; ColliderShape._tempVector30 = new Vector3(); class StaticPlaneColliderShape extends ColliderShape { constructor(normal, offset) { super(); this._normal = normal; this._offset = offset; this._type = ColliderShape.SHAPETYPES_STATICPLANE; var bt = ILaya3D.Physics3D._bullet; bt.btVector3_setValue(StaticPlaneColliderShape._btNormal, -normal.x, normal.y, normal.z); this._btShape = bt.btStaticPlaneShape_create(StaticPlaneColliderShape._btNormal, offset); } static __init__() { StaticPlaneColliderShape._btNormal = ILaya3D.Physics3D._bullet.btVector3_create(0, 0, 0); } clone() { var dest = new StaticPlaneColliderShape(this._normal, this._offset); this.cloneTo(dest); return dest; } } class CompoundColliderShape extends ColliderShape { constructor() { super(); this._childColliderShapes = []; this._type = ColliderShape.SHAPETYPES_COMPOUND; this._btShape = ILaya3D.Physics3D._bullet.btCompoundShape_create(); } static __init__() { var bt = ILaya3D.Physics3D._bullet; CompoundColliderShape._btVector3One = bt.btVector3_create(1, 1, 1); CompoundColliderShape._btTransform = bt.btTransform_create(); CompoundColliderShape._btOffset = bt.btVector3_create(0, 0, 0); CompoundColliderShape._btRotation = bt.btQuaternion_create(0, 0, 0, 1); } _clearChildShape(shape) { shape._attatched = false; shape._compoundParent = null; shape._indexInCompound = -1; } _addReference() { } _removeReference() { } _updateChildTransform(shape) { var bt = ILaya3D.Physics3D._bullet; var offset = shape.localOffset; var rotation = shape.localRotation; var btOffset = ColliderShape._btVector30; var btQuaternion = ColliderShape._btQuaternion0; var btTransform = ColliderShape._btTransform0; bt.btVector3_setValue(btOffset, -offset.x, offset.y, offset.z); bt.btQuaternion_setValue(btQuaternion, -rotation.x, rotation.y, rotation.z, -rotation.w); bt.btTransform_setOrigin(btTransform, btOffset); bt.btTransform_setRotation(btTransform, btQuaternion); bt.btCompoundShape_updateChildTransform(this._btShape, shape._indexInCompound, btTransform, true); } addChildShape(shape) { if (shape._attatched) throw "CompoundColliderShape: this shape has attatched to other entity."; shape._attatched = true; shape._compoundParent = this; shape._indexInCompound = this._childColliderShapes.length; this._childColliderShapes.push(shape); var offset = shape.localOffset; var rotation = shape.localRotation; var bt = ILaya3D.Physics3D._bullet; bt.btVector3_setValue(CompoundColliderShape._btOffset, -offset.x, offset.y, offset.z); bt.btQuaternion_setValue(CompoundColliderShape._btRotation, -rotation.x, rotation.y, rotation.z, -rotation.w); bt.btTransform_setOrigin(CompoundColliderShape._btTransform, CompoundColliderShape._btOffset); bt.btTransform_setRotation(CompoundColliderShape._btTransform, CompoundColliderShape._btRotation); var btScale = bt.btCollisionShape_getLocalScaling(this._btShape); bt.btCollisionShape_setLocalScaling(this._btShape, CompoundColliderShape._btVector3One); bt.btCompoundShape_addChildShape(this._btShape, CompoundColliderShape._btTransform, shape._btShape); bt.btCollisionShape_setLocalScaling(this._btShape, btScale); (this._attatchedCollisionObject) && (this._attatchedCollisionObject.colliderShape = this); } removeChildShape(shape) { if (shape._compoundParent === this) { var index = shape._indexInCompound; this._clearChildShape(shape); var endShape = this._childColliderShapes[this._childColliderShapes.length - 1]; endShape._indexInCompound = index; this._childColliderShapes[index] = endShape; this._childColliderShapes.pop(); ILaya3D.Physics3D._bullet.btCompoundShape_removeChildShapeByIndex(this._btShape, index); } } clearChildShape() { for (var i = 0, n = this._childColliderShapes.length; i < n; i++) { this._clearChildShape(this._childColliderShapes[i]); ILaya3D.Physics3D._bullet.btCompoundShape_removeChildShapeByIndex(this._btShape, 0); } this._childColliderShapes.length = 0; } getChildShapeCount() { return this._childColliderShapes.length; } cloneTo(destObject) { var destCompoundColliderShape = destObject; destCompoundColliderShape.clearChildShape(); for (var i = 0, n = this._childColliderShapes.length; i < n; i++) destCompoundColliderShape.addChildShape(this._childColliderShapes[i].clone()); } clone() { var dest = new CompoundColliderShape(); this.cloneTo(dest); return dest; } destroy() { super.destroy(); for (var i = 0, n = this._childColliderShapes.length; i < n; i++) { var childShape = this._childColliderShapes[i]; if (childShape._referenceCount === 0) childShape.destroy(); } } } class Transform3D extends Laya.EventDispatcher { constructor(owner) { super(); this._localPosition = new Vector3(0, 0, 0); this._localRotation = new Quaternion(0, 0, 0, 1); this._localScale = new Vector3(1, 1, 1); this._localRotationEuler = new Vector3(0, 0, 0); this._localMatrix = new Matrix4x4(); this._position = new Vector3(0, 0, 0); this._rotation = new Quaternion(0, 0, 0, 1); this._scale = new Vector3(1, 1, 1); this._rotationEuler = new Vector3(0, 0, 0); this._worldMatrix = new Matrix4x4(); this._children = null; this._parent = null; this._dummy = null; this._transformFlag = 0; this._owner = owner; this._children = []; this._setTransformFlag(Transform3D.TRANSFORM_LOCALQUATERNION | Transform3D.TRANSFORM_LOCALEULER | Transform3D.TRANSFORM_LOCALMATRIX, false); this._setTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDEULER | Transform3D.TRANSFORM_WORLDSCALE | Transform3D.TRANSFORM_WORLDMATRIX, true); } get _isFrontFaceInvert() { var scale = this.getWorldLossyScale(); var isInvert = scale.x < 0; (scale.y < 0) && (isInvert = !isInvert); (scale.z < 0) && (isInvert = !isInvert); return isInvert; } get owner() { return this._owner; } get worldNeedUpdate() { return this._getTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX); } get localPositionX() { return this._localPosition.x; } set localPositionX(x) { this._localPosition.x = x; this.localPosition = this._localPosition; } get localPositionY() { return this._localPosition.y; } set localPositionY(y) { this._localPosition.y = y; this.localPosition = this._localPosition; } get localPositionZ() { return this._localPosition.z; } set localPositionZ(z) { this._localPosition.z = z; this.localPosition = this._localPosition; } get localPosition() { return this._localPosition; } set localPosition(value) { if (this._localPosition !== value) value.cloneTo(this._localPosition); this._setTransformFlag(Transform3D.TRANSFORM_LOCALMATRIX, true); this._onWorldPositionTransform(); } get localRotationX() { return this.localRotation.x; } set localRotationX(x) { this._localRotation.x = x; this.localRotation = this._localRotation; } get localRotationY() { return this.localRotation.y; } set localRotationY(y) { this._localRotation.y = y; this.localRotation = this._localRotation; } get localRotationZ() { return this.localRotation.z; } set localRotationZ(z) { this._localRotation.z = z; this.localRotation = this._localRotation; } get localRotationW() { return this.localRotation.w; } set localRotationW(w) { this._localRotation.w = w; this.localRotation = this._localRotation; } get localRotation() { if (this._getTransformFlag(Transform3D.TRANSFORM_LOCALQUATERNION)) { var eulerE = this._localRotationEuler; Quaternion.createFromYawPitchRoll(eulerE.y / Transform3D._angleToRandin, eulerE.x / Transform3D._angleToRandin, eulerE.z / Transform3D._angleToRandin, this._localRotation); this._setTransformFlag(Transform3D.TRANSFORM_LOCALQUATERNION, false); } return this._localRotation; } set localRotation(value) { if (this._localRotation !== value) value.cloneTo(this._localRotation); this._localRotation.normalize(this._localRotation); this._setTransformFlag(Transform3D.TRANSFORM_LOCALEULER | Transform3D.TRANSFORM_LOCALMATRIX, true); this._setTransformFlag(Transform3D.TRANSFORM_LOCALQUATERNION, false); this._onWorldRotationTransform(); } get localScaleX() { return this._localScale.x; } set localScaleX(value) { this._localScale.x = value; this.localScale = this._localScale; } get localScaleY() { return this._localScale.y; } set localScaleY(value) { this._localScale.y = value; this.localScale = this._localScale; } get localScaleZ() { return this._localScale.z; } set localScaleZ(value) { this._localScale.z = value; this.localScale = this._localScale; } get localScale() { return this._localScale; } set localScale(value) { if (this._localScale !== value) value.cloneTo(this._localScale); this._setTransformFlag(Transform3D.TRANSFORM_LOCALMATRIX, true); this._onWorldScaleTransform(); } get localRotationEulerX() { return this.localRotationEuler.x; } set localRotationEulerX(value) { this._localRotationEuler.x = value; this.localRotationEuler = this._localRotationEuler; } get localRotationEulerY() { return this.localRotationEuler.y; } set localRotationEulerY(value) { this._localRotationEuler.y = value; this.localRotationEuler = this._localRotationEuler; } get localRotationEulerZ() { return this.localRotationEuler.z; } set localRotationEulerZ(value) { this._localRotationEuler.z = value; this.localRotationEuler = this._localRotationEuler; } get localRotationEuler() { if (this._getTransformFlag(Transform3D.TRANSFORM_LOCALEULER)) { this._localRotation.getYawPitchRoll(Transform3D._tempVector30); var euler = Transform3D._tempVector30; var localRotationEuler = this._localRotationEuler; localRotationEuler.x = euler.y * Transform3D._angleToRandin; localRotationEuler.y = euler.x * Transform3D._angleToRandin; localRotationEuler.z = euler.z * Transform3D._angleToRandin; this._setTransformFlag(Transform3D.TRANSFORM_LOCALEULER, false); } return this._localRotationEuler; } set localRotationEuler(value) { if (this._localRotationEuler !== value) value.cloneTo(this._localRotationEuler); this._setTransformFlag(Transform3D.TRANSFORM_LOCALEULER, false); this._setTransformFlag(Transform3D.TRANSFORM_LOCALQUATERNION | Transform3D.TRANSFORM_LOCALMATRIX, true); this._onWorldRotationTransform(); } get localMatrix() { if (this._getTransformFlag(Transform3D.TRANSFORM_LOCALMATRIX)) { Matrix4x4.createAffineTransformation(this._localPosition, this.localRotation, this._localScale, this._localMatrix); this._setTransformFlag(Transform3D.TRANSFORM_LOCALMATRIX, false); } return this._localMatrix; } set localMatrix(value) { if (this._localMatrix !== value) value.cloneTo(this._localMatrix); this._localMatrix.decomposeTransRotScale(this._localPosition, this._localRotation, this._localScale); this._setTransformFlag(Transform3D.TRANSFORM_LOCALEULER, true); this._setTransformFlag(Transform3D.TRANSFORM_LOCALMATRIX, false); this._onWorldTransform(); } get position() { if (this._getTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION)) { if (this._parent != null) { var worldMatE = this.worldMatrix.elements; this._position.x = worldMatE[12]; this._position.y = worldMatE[13]; this._position.z = worldMatE[14]; } else { this._localPosition.cloneTo(this._position); } this._setTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION, false); } return this._position; } set position(value) { if (this._parent != null) { var parentInvMat = Transform3D._tempMatrix0; this._parent.worldMatrix.invert(parentInvMat); Vector3.transformCoordinate(value, parentInvMat, this._localPosition); } else { value.cloneTo(this._localPosition); } this.localPosition = this._localPosition; if (this._position !== value) value.cloneTo(this._position); this._setTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION, false); } get rotation() { if (this._getTransformFlag(Transform3D.TRANSFORM_WORLDQUATERNION)) { if (this._parent != null) Quaternion.multiply(this._parent.rotation, this.localRotation, this._rotation); else this.localRotation.cloneTo(this._rotation); this._setTransformFlag(Transform3D.TRANSFORM_WORLDQUATERNION, false); } return this._rotation; } set rotation(value) { if (this._parent != null) { this._parent.rotation.invert(Transform3D._tempQuaternion0); Quaternion.multiply(Transform3D._tempQuaternion0, value, this._localRotation); } else { value.cloneTo(this._localRotation); } this.localRotation = this._localRotation; if (value !== this._rotation) value.cloneTo(this._rotation); this._setTransformFlag(Transform3D.TRANSFORM_WORLDQUATERNION, false); } get rotationEuler() { if (this._getTransformFlag(Transform3D.TRANSFORM_WORLDEULER)) { this.rotation.getYawPitchRoll(Transform3D._tempVector30); var eulerE = Transform3D._tempVector30; var rotationEulerE = this._rotationEuler; rotationEulerE.x = eulerE.y * Transform3D._angleToRandin; rotationEulerE.y = eulerE.x * Transform3D._angleToRandin; rotationEulerE.z = eulerE.z * Transform3D._angleToRandin; this._setTransformFlag(Transform3D.TRANSFORM_WORLDEULER, false); } return this._rotationEuler; } set rotationEuler(value) { Quaternion.createFromYawPitchRoll(value.y / Transform3D._angleToRandin, value.x / Transform3D._angleToRandin, value.z / Transform3D._angleToRandin, this._rotation); this.rotation = this._rotation; if (this._rotationEuler !== value) value.cloneTo(this._rotationEuler); this._setTransformFlag(Transform3D.TRANSFORM_WORLDEULER, false); } get worldMatrix() { if (this._getTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX)) { if (this._parent != null) Matrix4x4.multiply(this._parent.worldMatrix, this.localMatrix, this._worldMatrix); else this.localMatrix.cloneTo(this._worldMatrix); this._setTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX, false); } return this._worldMatrix; } set worldMatrix(value) { if (this._parent === null) { value.cloneTo(this._localMatrix); } else { this._parent.worldMatrix.invert(this._localMatrix); Matrix4x4.multiply(this._localMatrix, value, this._localMatrix); } this.localMatrix = this._localMatrix; if (this._worldMatrix !== value) value.cloneTo(this._worldMatrix); this._setTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX, false); } _getScaleMatrix() { var invRotation = Transform3D._tempQuaternion0; var invRotationMat = Transform3D._tempMatrix3x30; var worldRotScaMat = Transform3D._tempMatrix3x31; var scaMat = Transform3D._tempMatrix3x32; Matrix3x3.createFromMatrix4x4(this.worldMatrix, worldRotScaMat); this.rotation.invert(invRotation); Matrix3x3.createRotationQuaternion(invRotation, invRotationMat); Matrix3x3.multiply(invRotationMat, worldRotScaMat, scaMat); return scaMat; } _setTransformFlag(type, value) { if (value) this._transformFlag |= type; else this._transformFlag &= ~type; } _getTransformFlag(type) { return (this._transformFlag & type) != 0; } _setParent(value) { if (this._parent !== value) { if (this._parent) { var parentChilds = this._parent._children; var index = parentChilds.indexOf(this); parentChilds.splice(index, 1); } if (value) { value._children.push(this); (value) && (this._onWorldTransform()); } this._parent = value; } } _onWorldPositionRotationTransform() { if (!this._getTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDQUATERNION) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDEULER)) { this._setTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX | Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDEULER, true); this.event(Laya.Event.TRANSFORM_CHANGED, this._transformFlag); for (var i = 0, n = this._children.length; i < n; i++) this._children[i]._onWorldPositionRotationTransform(); } } _onWorldPositionScaleTransform() { if (!this._getTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDSCALE)) { this._setTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX | Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDSCALE, true); this.event(Laya.Event.TRANSFORM_CHANGED, this._transformFlag); for (var i = 0, n = this._children.length; i < n; i++) this._children[i]._onWorldPositionScaleTransform(); } } _onWorldPositionTransform() { if (!this._getTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION)) { this._setTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX | Transform3D.TRANSFORM_WORLDPOSITION, true); this.event(Laya.Event.TRANSFORM_CHANGED, this._transformFlag); for (var i = 0, n = this._children.length; i < n; i++) this._children[i]._onWorldPositionTransform(); } } _onWorldRotationTransform() { if (!this._getTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDQUATERNION) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDEULER)) { this._setTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDEULER, true); this.event(Laya.Event.TRANSFORM_CHANGED, this._transformFlag); for (var i = 0, n = this._children.length; i < n; i++) this._children[i]._onWorldPositionRotationTransform(); } } _onWorldScaleTransform() { if (!this._getTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDSCALE)) { this._setTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX | Transform3D.TRANSFORM_WORLDSCALE, true); this.event(Laya.Event.TRANSFORM_CHANGED, this._transformFlag); for (var i = 0, n = this._children.length; i < n; i++) this._children[i]._onWorldPositionScaleTransform(); } } _onWorldTransform() { if (!this._getTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDQUATERNION) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDEULER) || !this._getTransformFlag(Transform3D.TRANSFORM_WORLDSCALE)) { this._setTransformFlag(Transform3D.TRANSFORM_WORLDMATRIX | Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDEULER | Transform3D.TRANSFORM_WORLDSCALE, true); this.event(Laya.Event.TRANSFORM_CHANGED, this._transformFlag); for (var i = 0, n = this._children.length; i < n; i++) this._children[i]._onWorldTransform(); } } translate(translation, isLocal = true) { if (isLocal) { Matrix4x4.createFromQuaternion(this.localRotation, Transform3D._tempMatrix0); Vector3.transformCoordinate(translation, Transform3D._tempMatrix0, Transform3D._tempVector30); Vector3.add(this.localPosition, Transform3D._tempVector30, this._localPosition); this.localPosition = this._localPosition; } else { Vector3.add(this.position, translation, this._position); this.position = this._position; } } rotate(rotation, isLocal = true, isRadian = true) { var rot; if (isRadian) { rot = rotation; } else { Vector3.scale(rotation, Math.PI / 180.0, Transform3D._tempVector30); rot = Transform3D._tempVector30; } Quaternion.createFromYawPitchRoll(rot.y, rot.x, rot.z, Transform3D._tempQuaternion0); if (isLocal) { Quaternion.multiply(this._localRotation, Transform3D._tempQuaternion0, this._localRotation); this.localRotation = this._localRotation; } else { Quaternion.multiply(Transform3D._tempQuaternion0, this.rotation, this._rotation); this.rotation = this._rotation; } } getForward(forward) { var worldMatElem = this.worldMatrix.elements; forward.x = -worldMatElem[8]; forward.y = -worldMatElem[9]; forward.z = -worldMatElem[10]; } getUp(up) { var worldMatElem = this.worldMatrix.elements; up.x = worldMatElem[4]; up.y = worldMatElem[5]; up.z = worldMatElem[6]; } getRight(right) { var worldMatElem = this.worldMatrix.elements; right.x = worldMatElem[0]; right.y = worldMatElem[1]; right.z = worldMatElem[2]; } lookAt(target, up, isLocal = false) { var eye; if (isLocal) { eye = this._localPosition; if (Math.abs(eye.x - target.x) < MathUtils3D.zeroTolerance && Math.abs(eye.y - target.y) < MathUtils3D.zeroTolerance && Math.abs(eye.z - target.z) < MathUtils3D.zeroTolerance) return; Quaternion.lookAt(this._localPosition, target, up, this._localRotation); this._localRotation.invert(this._localRotation); this.localRotation = this._localRotation; } else { var worldPosition = this.position; eye = worldPosition; if (Math.abs(eye.x - target.x) < MathUtils3D.zeroTolerance && Math.abs(eye.y - target.y) < MathUtils3D.zeroTolerance && Math.abs(eye.z - target.z) < MathUtils3D.zeroTolerance) return; Quaternion.lookAt(worldPosition, target, up, this._rotation); this._rotation.invert(this._rotation); this.rotation = this._rotation; } } getWorldLossyScale() { if (this._getTransformFlag(Transform3D.TRANSFORM_WORLDSCALE)) { if (this._parent !== null) { var scaMatE = this._getScaleMatrix().elements; this._scale.x = scaMatE[0]; this._scale.y = scaMatE[4]; this._scale.z = scaMatE[8]; } else { this._localScale.cloneTo(this._scale); } this._setTransformFlag(Transform3D.TRANSFORM_WORLDSCALE, false); } return this._scale; } setWorldLossyScale(value) { if (this._parent !== null) { var scaleMat = Transform3D._tempMatrix3x33; var localScaleMat = Transform3D._tempMatrix3x33; var localScaleMatE = localScaleMat.elements; var parInvScaleMat = this._parent._getScaleMatrix(); parInvScaleMat.invert(parInvScaleMat); Matrix3x3.createFromScaling(value, scaleMat); Matrix3x3.multiply(parInvScaleMat, scaleMat, localScaleMat); this._localScale.x = localScaleMatE[0]; this._localScale.y = localScaleMatE[4]; this._localScale.z = localScaleMatE[8]; } else { value.cloneTo(this._localScale); } this.localScale = this._localScale; if (this._scale !== value) value.cloneTo(this._scale); this._setTransformFlag(Transform3D.TRANSFORM_WORLDSCALE, false); } get scale() { console.warn("Transfrm3D: discard function,please use getWorldLossyScale instead."); return this.getWorldLossyScale(); } set scale(value) { console.warn("Transfrm3D: discard function,please use setWorldLossyScale instead."); this.setWorldLossyScale(value); } } Transform3D._tempVector30 = new Vector3(); Transform3D._tempQuaternion0 = new Quaternion(); Transform3D._tempMatrix0 = new Matrix4x4(); Transform3D._tempMatrix3x30 = new Matrix3x3(); Transform3D._tempMatrix3x31 = new Matrix3x3(); Transform3D._tempMatrix3x32 = new Matrix3x3(); Transform3D._tempMatrix3x33 = new Matrix3x3(); Transform3D.TRANSFORM_LOCALQUATERNION = 0x01; Transform3D.TRANSFORM_LOCALEULER = 0x02; Transform3D.TRANSFORM_LOCALMATRIX = 0x04; Transform3D.TRANSFORM_WORLDPOSITION = 0x08; Transform3D.TRANSFORM_WORLDQUATERNION = 0x10; Transform3D.TRANSFORM_WORLDSCALE = 0x20; Transform3D.TRANSFORM_WORLDMATRIX = 0x40; Transform3D.TRANSFORM_WORLDEULER = 0x80; Transform3D._angleToRandin = 180 / Math.PI; class Physics3DUtils { constructor() { } static setColliderCollision(collider1, collider2, collsion) { } static getIColliderCollision(collider1, collider2) { return false; } } Physics3DUtils.COLLISIONFILTERGROUP_DEFAULTFILTER = 0x1; Physics3DUtils.COLLISIONFILTERGROUP_STATICFILTER = 0x2; Physics3DUtils.COLLISIONFILTERGROUP_KINEMATICFILTER = 0x4; Physics3DUtils.COLLISIONFILTERGROUP_DEBRISFILTER = 0x8; Physics3DUtils.COLLISIONFILTERGROUP_SENSORTRIGGER = 0x10; Physics3DUtils.COLLISIONFILTERGROUP_CHARACTERFILTER = 0x20; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER1 = 0x40; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER2 = 0x80; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER3 = 0x100; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER4 = 0x200; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER5 = 0x400; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER6 = 0x800; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER7 = 0x1000; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER8 = 0x2000; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER9 = 0x4000; Physics3DUtils.COLLISIONFILTERGROUP_CUSTOMFILTER10 = 0x8000; Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER = -1; Physics3DUtils.gravity = new Vector3(0, -9.81, 0); class BoxColliderShape extends ColliderShape { constructor(sizeX = 1.0, sizeY = 1.0, sizeZ = 1.0) { super(); this._sizeX = sizeX; this._sizeY = sizeY; this._sizeZ = sizeZ; this._type = ColliderShape.SHAPETYPES_BOX; var bt = ILaya3D.Physics3D._bullet; bt.btVector3_setValue(BoxColliderShape._btSize, sizeX / 2, sizeY / 2, sizeZ / 2); this._btShape = bt.btBoxShape_create(BoxColliderShape._btSize); } static __init__() { BoxColliderShape._btSize = ILaya3D.Physics3D._bullet.btVector3_create(0, 0, 0); } get sizeX() { return this._sizeX; } get sizeY() { return this._sizeY; } get sizeZ() { return this._sizeZ; } clone() { var dest = new BoxColliderShape(this._sizeX, this._sizeY, this._sizeZ); this.cloneTo(dest); return dest; } } class CapsuleColliderShape extends ColliderShape { constructor(radius = 0.5, length = 1.25, orientation = ColliderShape.SHAPEORIENTATION_UPY) { super(); this._radius = radius; this._length = length; this._orientation = orientation; this._type = ColliderShape.SHAPETYPES_CAPSULE; var bt = ILaya3D.Physics3D._bullet; switch (orientation) { case ColliderShape.SHAPEORIENTATION_UPX: this._btShape = bt.btCapsuleShapeX_create(radius, length - radius * 2); break; case ColliderShape.SHAPEORIENTATION_UPY: this._btShape = bt.btCapsuleShape_create(radius, length - radius * 2); break; case ColliderShape.SHAPEORIENTATION_UPZ: this._btShape = bt.btCapsuleShapeZ_create(radius, length - radius * 2); break; default: throw "CapsuleColliderShape:unknown orientation."; } } get radius() { return this._radius; } get length() { return this._length; } get orientation() { return this._orientation; } _setScale(value) { var fixScale = CapsuleColliderShape._tempVector30; switch (this.orientation) { case ColliderShape.SHAPEORIENTATION_UPX: fixScale.x = value.x; fixScale.y = fixScale.z = Math.max(value.y, value.z); break; case ColliderShape.SHAPEORIENTATION_UPY: fixScale.y = value.y; fixScale.x = fixScale.z = Math.max(value.x, value.z); break; case ColliderShape.SHAPEORIENTATION_UPZ: fixScale.z = value.z; fixScale.x = fixScale.y = Math.max(value.x, value.y); break; default: throw "CapsuleColliderShape:unknown orientation."; } super._setScale(fixScale); } clone() { var dest = new CapsuleColliderShape(this._radius, this._length, this._orientation); this.cloneTo(dest); return dest; } } CapsuleColliderShape._tempVector30 = new Vector3(); class ConeColliderShape extends ColliderShape { constructor(radius = 0.5, height = 1.0, orientation = ColliderShape.SHAPEORIENTATION_UPY) { super(); this._radius = 1; this._height = 0.5; this._radius = radius; this._height = height; this._orientation = orientation; this._type = ColliderShape.SHAPETYPES_CYLINDER; var bt = ILaya3D.Physics3D._bullet; switch (orientation) { case ColliderShape.SHAPEORIENTATION_UPX: this._btShape = bt.btConeShapeX_create(radius, height); break; case ColliderShape.SHAPEORIENTATION_UPY: this._btShape = bt.btConeShape_create(radius, height); break; case ColliderShape.SHAPEORIENTATION_UPZ: this._btShape = bt.btConeShapeZ_create(radius, height); break; default: throw "ConeColliderShape:unknown orientation."; } } get radius() { return this._radius; } get height() { return this._height; } get orientation() { return this._orientation; } clone() { var dest = new ConeColliderShape(this._radius, this._height, this._orientation); this.cloneTo(dest); return dest; } } class CylinderColliderShape extends ColliderShape { constructor(radius = 0.5, height = 1.0, orientation = ColliderShape.SHAPEORIENTATION_UPY) { super(); this._radius = 1; this._height = 0.5; this._radius = radius; this._height = height; this._orientation = orientation; this._type = ColliderShape.SHAPETYPES_CYLINDER; var bt = ILaya3D.Physics3D._bullet; switch (orientation) { case ColliderShape.SHAPEORIENTATION_UPX: bt.btVector3_setValue(CylinderColliderShape._btSize, height / 2, radius, radius); this._btShape = bt.btCylinderShapeX_create(CylinderColliderShape._btSize); break; case ColliderShape.SHAPEORIENTATION_UPY: bt.btVector3_setValue(CylinderColliderShape._btSize, radius, height / 2, radius); this._btShape = bt.btCylinderShape_create(CylinderColliderShape._btSize); break; case ColliderShape.SHAPEORIENTATION_UPZ: bt.btVector3_setValue(CylinderColliderShape._btSize, radius, radius, height / 2); this._btShape = bt.btCylinderShapeZ_create(CylinderColliderShape._btSize); break; default: throw "CapsuleColliderShape:unknown orientation."; } } static __init__() { CylinderColliderShape._btSize = ILaya3D.Physics3D._bullet.btVector3_create(0, 0, 0); } get radius() { return this._radius; } get height() { return this._height; } get orientation() { return this._orientation; } clone() { var dest = new CylinderColliderShape(this._radius, this._height, this._orientation); this.cloneTo(dest); return dest; } } class MeshColliderShape extends ColliderShape { constructor() { super(); this._mesh = null; this._convex = false; } get mesh() { return this._mesh; } set mesh(value) { if (this._mesh !== value) { var bt = ILaya3D.Physics3D._bullet; if (this._mesh) { bt.btCollisionShape_destroy(this._btShape); } if (value) { this._btShape = bt.btGImpactMeshShape_create(value._getPhysicMesh()); bt.btGImpactShapeInterface_updateBound(this._btShape); } this._mesh = value; } } get convex() { return this._convex; } set convex(value) { this._convex = value; } _setScale(value) { if (this._compoundParent) { this.updateLocalTransformations(); } else { var bt = ILaya3D.Physics3D._bullet; bt.btVector3_setValue(ColliderShape._btScale, value.x, value.y, value.z); bt.btCollisionShape_setLocalScaling(this._btShape, ColliderShape._btScale); bt.btGImpactShapeInterface_updateBound(this._btShape); } } cloneTo(destObject) { var destMeshCollider = destObject; destMeshCollider.convex = this._convex; destMeshCollider.mesh = this._mesh; super.cloneTo(destObject); } clone() { var dest = new MeshColliderShape(); this.cloneTo(dest); return dest; } destroy() { if (this._btShape) { ILaya3D.Physics3D._bullet.btCollisionShape_destroy(this._btShape); this._btShape = null; } } } class SphereColliderShape extends ColliderShape { constructor(radius = 0.5) { super(); this._radius = radius; this._type = ColliderShape.SHAPETYPES_SPHERE; this._btShape = ILaya3D.Physics3D._bullet.btSphereShape_create(radius); } get radius() { return this._radius; } clone() { var dest = new SphereColliderShape(this._radius); this.cloneTo(dest); return dest; } } class PhysicsComponent extends Laya.Component { constructor(collisionGroup, canCollideWith) { super(); this._restitution = 0.0; this._friction = 0.5; this._rollingFriction = 0.0; this._ccdMotionThreshold = 0.0; this._ccdSweptSphereRadius = 0.0; this._collisionGroup = Physics3DUtils.COLLISIONFILTERGROUP_DEFAULTFILTER; this._canCollideWith = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER; this._colliderShape = null; this._transformFlag = 2147483647; this._controlBySimulation = false; this._enableProcessCollisions = true; this._inPhysicUpdateListIndex = -1; this.canScaleShape = true; this._collisionGroup = collisionGroup; this._canCollideWith = canCollideWith; PhysicsComponent._physicObjectsMap[this.id] = this; } static __init__() { var bt = ILaya3D.Physics3D._bullet; PhysicsComponent._btVector30 = bt.btVector3_create(0, 0, 0); PhysicsComponent._btQuaternion0 = bt.btQuaternion_create(0, 0, 0, 1); } static _createAffineTransformationArray(tranX, tranY, tranZ, rotX, rotY, rotZ, rotW, scale, outE) { var x2 = rotX + rotX, y2 = rotY + rotY, z2 = rotZ + rotZ; var xx = rotX * x2, xy = rotX * y2, xz = rotX * z2, yy = rotY * y2, yz = rotY * z2, zz = rotZ * z2; var wx = rotW * x2, wy = rotW * y2, wz = rotW * z2, sx = scale[0], sy = scale[1], sz = scale[2]; outE[0] = (1 - (yy + zz)) * sx; outE[1] = (xy + wz) * sx; outE[2] = (xz - wy) * sx; outE[3] = 0; outE[4] = (xy - wz) * sy; outE[5] = (1 - (xx + zz)) * sy; outE[6] = (yz + wx) * sy; outE[7] = 0; outE[8] = (xz + wy) * sz; outE[9] = (yz - wx) * sz; outE[10] = (1 - (xx + yy)) * sz; outE[11] = 0; outE[12] = tranX; outE[13] = tranY; outE[14] = tranZ; outE[15] = 1; } static _creatShape(shapeData) { var colliderShape; switch (shapeData.type) { case "BoxColliderShape": var sizeData = shapeData.size; colliderShape = sizeData ? new BoxColliderShape(sizeData[0], sizeData[1], sizeData[2]) : new BoxColliderShape(); break; case "SphereColliderShape": colliderShape = new SphereColliderShape(shapeData.radius); break; case "CapsuleColliderShape": colliderShape = new CapsuleColliderShape(shapeData.radius, shapeData.height, shapeData.orientation); break; case "MeshColliderShape": var meshCollider = new MeshColliderShape(); shapeData.mesh && (meshCollider.mesh = Laya.Loader.getRes(shapeData.mesh)); colliderShape = meshCollider; break; case "ConeColliderShape": colliderShape = new ConeColliderShape(shapeData.radius, shapeData.height, shapeData.orientation); break; case "CylinderColliderShape": colliderShape = new CylinderColliderShape(shapeData.radius, shapeData.height, shapeData.orientation); break; default: throw "unknown shape type."; } if (shapeData.center) { var localOffset = colliderShape.localOffset; localOffset.fromArray(shapeData.center); colliderShape.localOffset = localOffset; } return colliderShape; } static physicVector3TransformQuat(source, qx, qy, qz, qw, out) { var x = source.x, y = source.y, z = source.z, ix = qw * x + qy * z - qz * y, iy = qw * y + qz * x - qx * z, iz = qw * z + qx * y - qy * x, iw = -qx * x - qy * y - qz * z; out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; } static physicQuaternionMultiply(lx, ly, lz, lw, right, out) { var rx = right.x; var ry = right.y; var rz = right.z; var rw = right.w; var a = (ly * rz - lz * ry); var b = (lz * rx - lx * rz); var c = (lx * ry - ly * rx); var d = (lx * rx + ly * ry + lz * rz); out.x = (lx * rw + rx * lw) + a; out.y = (ly * rw + ry * lw) + b; out.z = (lz * rw + rz * lw) + c; out.w = lw * rw - d; } get restitution() { return this._restitution; } set restitution(value) { this._restitution = value; this._btColliderObject && ILaya3D.Physics3D._bullet.btCollisionObject_setRestitution(this._btColliderObject, value); } get friction() { return this._friction; } set friction(value) { this._friction = value; this._btColliderObject && ILaya3D.Physics3D._bullet.btCollisionObject_setFriction(this._btColliderObject, value); } get rollingFriction() { return this._rollingFriction; } set rollingFriction(value) { this._rollingFriction = value; this._btColliderObject && ILaya3D.Physics3D._bullet.btCollisionObject_setRollingFriction(this._btColliderObject, value); } get ccdMotionThreshold() { return this._ccdMotionThreshold; } set ccdMotionThreshold(value) { this._ccdMotionThreshold = value; this._btColliderObject && ILaya3D.Physics3D._bullet.btCollisionObject_setCcdMotionThreshold(this._btColliderObject, value); } get ccdSweptSphereRadius() { return this._ccdSweptSphereRadius; } set ccdSweptSphereRadius(value) { this._ccdSweptSphereRadius = value; this._btColliderObject && ILaya3D.Physics3D._bullet.btCollisionObject_setCcdSweptSphereRadius(this._btColliderObject, value); } get isActive() { return this._btColliderObject ? ILaya3D.Physics3D._bullet.btCollisionObject_isActive(this._btColliderObject) : false; } get colliderShape() { return this._colliderShape; } set colliderShape(value) { var lastColliderShape = this._colliderShape; if (lastColliderShape) { lastColliderShape._attatched = false; lastColliderShape._attatchedCollisionObject = null; } this._colliderShape = value; if (value) { if (value._attatched) { throw "PhysicsComponent: this shape has attatched to other entity."; } else { value._attatched = true; value._attatchedCollisionObject = this; } if (this._btColliderObject) { ILaya3D.Physics3D._bullet.btCollisionObject_setCollisionShape(this._btColliderObject, value._btShape); var canInSimulation = this._simulation && this._enabled; (canInSimulation && lastColliderShape) && (this._removeFromSimulation()); this._onShapeChange(value); if (canInSimulation) { this._derivePhysicsTransformation(true); this._addToSimulation(); } } } else { if (this._simulation && this._enabled) lastColliderShape && this._removeFromSimulation(); } } get simulation() { return this._simulation; } get collisionGroup() { return this._collisionGroup; } set collisionGroup(value) { if (this._collisionGroup !== value) { this._collisionGroup = value; if (this._simulation && this._colliderShape && this._enabled) { this._removeFromSimulation(); this._addToSimulation(); } } } get canCollideWith() { return this._canCollideWith; } set canCollideWith(value) { if (this._canCollideWith !== value) { this._canCollideWith = value; if (this._simulation && this._colliderShape && this._enabled) { this._removeFromSimulation(); this._addToSimulation(); } } } _parseShape(shapesData) { var shapeCount = shapesData.length; if (shapeCount === 1) { var shape = PhysicsComponent._creatShape(shapesData[0]); this.colliderShape = shape; } else { var compoundShape = new CompoundColliderShape(); for (var i = 0; i < shapeCount; i++) { shape = PhysicsComponent._creatShape(shapesData[i]); compoundShape.addChildShape(shape); } this.colliderShape = compoundShape; } } _onScaleChange(scale) { this._colliderShape._setScale(scale); } _onEnable() { this._simulation = this.owner._scene.physicsSimulation; ILaya3D.Physics3D._bullet.btCollisionObject_setContactProcessingThreshold(this._btColliderObject, 1e30); if (this._colliderShape) { this._derivePhysicsTransformation(true); this._addToSimulation(); } } _onDisable() { if (this._colliderShape) { this._removeFromSimulation(); (this._inPhysicUpdateListIndex !== -1) && (this._simulation._physicsUpdateList.remove(this)); } this._simulation = null; } _onDestroy() { delete PhysicsComponent._physicObjectsMap[this.id]; ILaya3D.Physics3D._bullet.btCollisionObject_destroy(this._btColliderObject); this._colliderShape.destroy(); super._onDestroy(); this._btColliderObject = null; this._colliderShape = null; this._simulation = null; this.owner.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onTransformChanged); } _isValid() { return this._simulation && this._colliderShape && this._enabled; } _parse(data) { (data.collisionGroup != null) && (this.collisionGroup = data.collisionGroup); (data.canCollideWith != null) && (this.canCollideWith = data.canCollideWith); (data.ccdMotionThreshold != null) && (this.ccdMotionThreshold = data.ccdMotionThreshold); (data.ccdSweptSphereRadius != null) && (this.ccdSweptSphereRadius = data.ccdSweptSphereRadius); } _setTransformFlag(type, value) { if (value) this._transformFlag |= type; else this._transformFlag &= ~type; } _getTransformFlag(type) { return (this._transformFlag & type) != 0; } _addToSimulation() { } _removeFromSimulation() { } _derivePhysicsTransformation(force) { var bt = ILaya3D.Physics3D._bullet; var btColliderObject = this._btColliderObject; var btTransform = bt.btCollisionObject_getWorldTransform(btColliderObject); this._innerDerivePhysicsTransformation(btTransform, force); bt.btCollisionObject_setWorldTransform(btColliderObject, btTransform); } _innerDerivePhysicsTransformation(physicTransformOut, force) { var bt = ILaya3D.Physics3D._bullet; var transform = this.owner._transform; if (force || this._getTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION)) { var shapeOffset = this._colliderShape.localOffset; var position = transform.position; var btPosition = PhysicsComponent._btVector30; if (shapeOffset.x !== 0 || shapeOffset.y !== 0 || shapeOffset.z !== 0) { var physicPosition = PhysicsComponent._tempVector30; var worldMat = transform.worldMatrix; Vector3.transformCoordinate(shapeOffset, worldMat, physicPosition); bt.btVector3_setValue(btPosition, -physicPosition.x, physicPosition.y, physicPosition.z); } else { bt.btVector3_setValue(btPosition, -position.x, position.y, position.z); } bt.btTransform_setOrigin(physicTransformOut, btPosition); this._setTransformFlag(Transform3D.TRANSFORM_WORLDPOSITION, false); } if (force || this._getTransformFlag(Transform3D.TRANSFORM_WORLDQUATERNION)) { var shapeRotation = this._colliderShape.localRotation; var btRotation = PhysicsComponent._btQuaternion0; var rotation = transform.rotation; if (shapeRotation.x !== 0 || shapeRotation.y !== 0 || shapeRotation.z !== 0 || shapeRotation.w !== 1) { var physicRotation = PhysicsComponent._tempQuaternion0; PhysicsComponent.physicQuaternionMultiply(rotation.x, rotation.y, rotation.z, rotation.w, shapeRotation, physicRotation); bt.btQuaternion_setValue(btRotation, -physicRotation.x, physicRotation.y, physicRotation.z, -physicRotation.w); } else { bt.btQuaternion_setValue(btRotation, -rotation.x, rotation.y, rotation.z, -rotation.w); } bt.btTransform_setRotation(physicTransformOut, btRotation); this._setTransformFlag(Transform3D.TRANSFORM_WORLDQUATERNION, false); } if (force || this._getTransformFlag(Transform3D.TRANSFORM_WORLDSCALE)) { this._onScaleChange(transform.getWorldLossyScale()); this._setTransformFlag(Transform3D.TRANSFORM_WORLDSCALE, false); } } _updateTransformComponent(physicsTransform) { var bt = ILaya3D.Physics3D._bullet; var colliderShape = this._colliderShape; var localOffset = colliderShape.localOffset; var localRotation = colliderShape.localRotation; var transform = this.owner._transform; var position = transform.position; var rotation = transform.rotation; var btPosition = bt.btTransform_getOrigin(physicsTransform); var btRotation = bt.btTransform_getRotation(physicsTransform); var btRotX = -bt.btQuaternion_x(btRotation); var btRotY = bt.btQuaternion_y(btRotation); var btRotZ = bt.btQuaternion_z(btRotation); var btRotW = -bt.btQuaternion_w(btRotation); if (localRotation.x !== 0 || localRotation.y !== 0 || localRotation.z !== 0 || localRotation.w !== 1) { var invertShapeRotaion = PhysicsComponent._tempQuaternion0; localRotation.invert(invertShapeRotaion); PhysicsComponent.physicQuaternionMultiply(btRotX, btRotY, btRotZ, btRotW, invertShapeRotaion, rotation); } else { rotation.x = btRotX; rotation.y = btRotY; rotation.z = btRotZ; rotation.w = btRotW; } transform.rotation = rotation; if (localOffset.x !== 0 || localOffset.y !== 0 || localOffset.z !== 0) { var btScale = bt.btCollisionShape_getLocalScaling(colliderShape._btShape); var rotShapePosition = PhysicsComponent._tempVector30; rotShapePosition.x = localOffset.x * bt.btVector3_x(btScale); rotShapePosition.y = localOffset.y * bt.btVector3_y(btScale); rotShapePosition.z = localOffset.z * bt.btVector3_z(btScale); Vector3.transformQuat(rotShapePosition, rotation, rotShapePosition); position.x = -bt.btVector3_x(btPosition) - rotShapePosition.x; position.y = bt.btVector3_y(btPosition) - rotShapePosition.y; position.z = bt.btVector3_z(btPosition) - rotShapePosition.z; } else { position.x = -bt.btVector3_x(btPosition); position.y = bt.btVector3_y(btPosition); position.z = bt.btVector3_z(btPosition); } transform.position = position; } _onShapeChange(colShape) { var btColObj = this._btColliderObject; var bt = ILaya3D.Physics3D._bullet; var flags = bt.btCollisionObject_getCollisionFlags(btColObj); if (colShape.needsCustomCollisionCallback) { if ((flags & PhysicsComponent.COLLISIONFLAGS_CUSTOM_MATERIAL_CALLBACK) === 0) bt.btCollisionObject_setCollisionFlags(btColObj, flags | PhysicsComponent.COLLISIONFLAGS_CUSTOM_MATERIAL_CALLBACK); } else { if ((flags & PhysicsComponent.COLLISIONFLAGS_CUSTOM_MATERIAL_CALLBACK) > 0) bt.btCollisionObject_setCollisionFlags(btColObj, flags ^ PhysicsComponent.COLLISIONFLAGS_CUSTOM_MATERIAL_CALLBACK); } } _onAdded() { this.enabled = this._enabled; this.restitution = this._restitution; this.friction = this._friction; this.rollingFriction = this._rollingFriction; this.ccdMotionThreshold = this._ccdMotionThreshold; this.ccdSweptSphereRadius = this._ccdSweptSphereRadius; this.owner.transform.on(Laya.Event.TRANSFORM_CHANGED, this, this._onTransformChanged); } _onTransformChanged(flag) { if (PhysicsComponent._addUpdateList || !this._controlBySimulation) { flag &= Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDSCALE; if (flag) { this._transformFlag |= flag; if (this._isValid() && this._inPhysicUpdateListIndex === -1) this._simulation._physicsUpdateList.add(this); } } } _cloneTo(dest) { var destPhysicsComponent = dest; destPhysicsComponent.restitution = this._restitution; destPhysicsComponent.friction = this._friction; destPhysicsComponent.rollingFriction = this._rollingFriction; destPhysicsComponent.ccdMotionThreshold = this._ccdMotionThreshold; destPhysicsComponent.ccdSweptSphereRadius = this._ccdSweptSphereRadius; destPhysicsComponent.collisionGroup = this._collisionGroup; destPhysicsComponent.canCollideWith = this._canCollideWith; destPhysicsComponent.canScaleShape = this.canScaleShape; (this._colliderShape) && (destPhysicsComponent.colliderShape = this._colliderShape.clone()); } } PhysicsComponent.ACTIVATIONSTATE_ACTIVE_TAG = 1; PhysicsComponent.ACTIVATIONSTATE_ISLAND_SLEEPING = 2; PhysicsComponent.ACTIVATIONSTATE_WANTS_DEACTIVATION = 3; PhysicsComponent.ACTIVATIONSTATE_DISABLE_DEACTIVATION = 4; PhysicsComponent.ACTIVATIONSTATE_DISABLE_SIMULATION = 5; PhysicsComponent.COLLISIONFLAGS_STATIC_OBJECT = 1; PhysicsComponent.COLLISIONFLAGS_KINEMATIC_OBJECT = 2; PhysicsComponent.COLLISIONFLAGS_NO_CONTACT_RESPONSE = 4; PhysicsComponent.COLLISIONFLAGS_CUSTOM_MATERIAL_CALLBACK = 8; PhysicsComponent.COLLISIONFLAGS_CHARACTER_OBJECT = 16; PhysicsComponent.COLLISIONFLAGS_DISABLE_VISUALIZE_OBJECT = 32; PhysicsComponent.COLLISIONFLAGS_DISABLE_SPU_COLLISION_PROCESSING = 64; PhysicsComponent._tempVector30 = new Vector3(); PhysicsComponent._tempQuaternion0 = new Quaternion(); PhysicsComponent._tempQuaternion1 = new Quaternion(); PhysicsComponent._tempMatrix4x40 = new Matrix4x4(); PhysicsComponent._physicObjectsMap = {}; PhysicsComponent._addUpdateList = true; class SingletonList { constructor() { this.elements = []; this.length = 0; } _add(element) { if (this.length === this.elements.length) this.elements.push(element); else this.elements[this.length] = element; } add(element) { if (this.length === this.elements.length) this.elements.push(element); else this.elements[this.length] = element; this.length++; } } class PhysicsUpdateList extends SingletonList { constructor() { super(); } add(element) { var index = element._inPhysicUpdateListIndex; if (index !== -1) throw "PhysicsUpdateList:element has in PhysicsUpdateList."; this._add(element); element._inPhysicUpdateListIndex = this.length++; } remove(element) { var index = element._inPhysicUpdateListIndex; this.length--; if (index !== this.length) { var end = this.elements[this.length]; this.elements[index] = end; end._inPhysicUpdateListIndex = index; } element._inPhysicUpdateListIndex = -1; } } class ContactPoint { constructor() { this._idCounter = 0; this.colliderA = null; this.colliderB = null; this.distance = 0; this.normal = new Vector3(); this.positionOnA = new Vector3(); this.positionOnB = new Vector3(); this._id = ++this._idCounter; } } class HitResult { constructor() { this.succeeded = false; this.collider = null; this.point = new Vector3(); this.normal = new Vector3(); this.hitFraction = 0; } } class Collision { constructor() { this._lastUpdateFrame = -2147483648; this._updateFrame = -2147483648; this._isTrigger = false; this.contacts = []; } _setUpdateFrame(farme) { this._lastUpdateFrame = this._updateFrame; this._updateFrame = farme; } } class CollisionTool { constructor() { this._hitResultsPoolIndex = 0; this._hitResultsPool = []; this._contactPonintsPoolIndex = 0; this._contactPointsPool = []; this._collisionsPool = []; this._collisions = {}; } getHitResult() { var hitResult = this._hitResultsPool[this._hitResultsPoolIndex++]; if (!hitResult) { hitResult = new HitResult(); this._hitResultsPool.push(hitResult); } return hitResult; } recoverAllHitResultsPool() { this._hitResultsPoolIndex = 0; } getContactPoints() { var contactPoint = this._contactPointsPool[this._contactPonintsPoolIndex++]; if (!contactPoint) { contactPoint = new ContactPoint(); this._contactPointsPool.push(contactPoint); } return contactPoint; } recoverAllContactPointsPool() { this._contactPonintsPoolIndex = 0; } getCollision(physicComponentA, physicComponentB) { var collision; var idA = physicComponentA.id; var idB = physicComponentB.id; var subCollisionFirst = this._collisions[idA]; if (subCollisionFirst) collision = subCollisionFirst[idB]; if (!collision) { if (!subCollisionFirst) { subCollisionFirst = {}; this._collisions[idA] = subCollisionFirst; } collision = this._collisionsPool.length === 0 ? new Collision() : this._collisionsPool.pop(); collision._colliderA = physicComponentA; collision._colliderB = physicComponentB; subCollisionFirst[idB] = collision; } return collision; } recoverCollision(collision) { var idA = collision._colliderA.id; var idB = collision._colliderB.id; this._collisions[idA][idB] = null; this._collisionsPool.push(collision); } garbageCollection() { this._hitResultsPoolIndex = 0; this._hitResultsPool.length = 0; this._contactPonintsPoolIndex = 0; this._contactPointsPool.length = 0; this._collisionsPool.length = 0; for (var subCollisionsKey in this._collisionsPool) { var subCollisions = this._collisionsPool[subCollisionsKey]; var wholeDelete = true; for (var collisionKey in subCollisions) { if (subCollisions[collisionKey]) wholeDelete = false; else delete subCollisions[collisionKey]; } if (wholeDelete) delete this._collisionsPool[subCollisionsKey]; } } } class PhysicsSimulation { constructor(configuration, flags = 0) { this._gravity = new Vector3(0, -10, 0); this._btVector3Zero = ILaya3D.Physics3D._bullet.btVector3_create(0, 0, 0); this._btDefaultQuaternion = ILaya3D.Physics3D._bullet.btQuaternion_create(0, 0, 0, -1); this._collisionsUtils = new CollisionTool(); this._previousFrameCollisions = []; this._currentFrameCollisions = []; this._currentConstraint = {}; this._physicsUpdateList = new PhysicsUpdateList(); this._characters = []; this._updatedRigidbodies = 0; this.maxSubSteps = 1; this.fixedTimeStep = 1.0 / 60.0; this.maxSubSteps = configuration.maxSubSteps; this.fixedTimeStep = configuration.fixedTimeStep; var bt = ILaya3D.Physics3D._bullet; this._btCollisionConfiguration = bt.btDefaultCollisionConfiguration_create(); this._btDispatcher = bt.btCollisionDispatcher_create(this._btCollisionConfiguration); this._btBroadphase = bt.btDbvtBroadphase_create(); bt.btOverlappingPairCache_setInternalGhostPairCallback(bt.btDbvtBroadphase_getOverlappingPairCache(this._btBroadphase), bt.btGhostPairCallback_create()); var conFlags = configuration.flags; if (conFlags & PhysicsSimulation.PHYSICSENGINEFLAGS_COLLISIONSONLY) { this._btCollisionWorld = new bt.btCollisionWorld(this._btDispatcher, this._btBroadphase, this._btCollisionConfiguration); } else if (conFlags & PhysicsSimulation.PHYSICSENGINEFLAGS_SOFTBODYSUPPORT) { throw "PhysicsSimulation:SoftBody processing is not yet available"; } else { var solver = bt.btSequentialImpulseConstraintSolver_create(); this._btDiscreteDynamicsWorld = bt.btDiscreteDynamicsWorld_create(this._btDispatcher, this._btBroadphase, solver, this._btCollisionConfiguration); this._btCollisionWorld = this._btDiscreteDynamicsWorld; } if (this._btDiscreteDynamicsWorld) { this._btSolverInfo = bt.btDynamicsWorld_getSolverInfo(this._btDiscreteDynamicsWorld); this._btDispatchInfo = bt.btCollisionWorld_getDispatchInfo(this._btDiscreteDynamicsWorld); } this._btClosestRayResultCallback = bt.ClosestRayResultCallback_create(this._btVector3Zero, this._btVector3Zero); this._btAllHitsRayResultCallback = bt.AllHitsRayResultCallback_create(this._btVector3Zero, this._btVector3Zero); this._btClosestConvexResultCallback = bt.ClosestConvexResultCallback_create(this._btVector3Zero, this._btVector3Zero); this._btAllConvexResultCallback = bt.AllConvexResultCallback_create(this._btVector3Zero, this._btVector3Zero); bt.btGImpactCollisionAlgorithm_RegisterAlgorithm(this._btDispatcher); } static __init__() { var bt = ILaya3D.Physics3D._bullet; PhysicsSimulation._btTempVector30 = bt.btVector3_create(0, 0, 0); PhysicsSimulation._btTempVector31 = bt.btVector3_create(0, 0, 0); PhysicsSimulation._btTempQuaternion0 = bt.btQuaternion_create(0, 0, 0, 1); PhysicsSimulation._btTempQuaternion1 = bt.btQuaternion_create(0, 0, 0, 1); PhysicsSimulation._btTempTransform0 = bt.btTransform_create(); PhysicsSimulation._btTempTransform1 = bt.btTransform_create(); } static createConstraint() { } get continuousCollisionDetection() { return ILaya3D.Physics3D._bullet.btCollisionWorld_get_m_useContinuous(this._btDispatchInfo); } set continuousCollisionDetection(value) { ILaya3D.Physics3D._bullet.btCollisionWorld_set_m_useContinuous(this._btDispatchInfo, value); } get gravity() { if (!this._btDiscreteDynamicsWorld) throw "Simulation:Cannot perform this action when the physics engine is set to CollisionsOnly"; return this._gravity; } set gravity(value) { if (!this._btDiscreteDynamicsWorld) throw "Simulation:Cannot perform this action when the physics engine is set to CollisionsOnly"; this._gravity = value; var bt = ILaya3D.Physics3D._bullet; var btGravity = PhysicsSimulation._btTempVector30; bt.btVector3_setValue(btGravity, -value.x, value.y, value.z); bt.btDiscreteDynamicsWorld_setGravity(this._btDiscreteDynamicsWorld, btGravity); } get speculativeContactRestitution() { if (!this._btDiscreteDynamicsWorld) throw "Simulation:Cannot Cannot perform this action when the physics engine is set to CollisionsOnly"; return ILaya3D.Physics3D._bullet.btDiscreteDynamicsWorld_getApplySpeculativeContactRestitution(this._btDiscreteDynamicsWorld); } set speculativeContactRestitution(value) { if (!this._btDiscreteDynamicsWorld) throw "Simulation:Cannot Cannot perform this action when the physics engine is set to CollisionsOnly"; ILaya3D.Physics3D._bullet.btDiscreteDynamicsWorld_setApplySpeculativeContactRestitution(this._btDiscreteDynamicsWorld, value); } _simulate(deltaTime) { this._updatedRigidbodies = 0; var bt = ILaya3D.Physics3D._bullet; if (this._btDiscreteDynamicsWorld) bt.btDiscreteDynamicsWorld_stepSimulation(this._btDiscreteDynamicsWorld, deltaTime, this.maxSubSteps, this.fixedTimeStep); else bt.PerformDiscreteCollisionDetection(this._btCollisionWorld); } _destroy() { var bt = ILaya3D.Physics3D._bullet; if (this._btDiscreteDynamicsWorld) { bt.btCollisionWorld_destroy(this._btDiscreteDynamicsWorld); this._btDiscreteDynamicsWorld = null; } else { bt.btCollisionWorld_destroy(this._btCollisionWorld); this._btCollisionWorld = null; } bt.btDbvtBroadphase_destroy(this._btBroadphase); this._btBroadphase = null; bt.btCollisionDispatcher_destroy(this._btDispatcher); this._btDispatcher = null; bt.btDefaultCollisionConfiguration_destroy(this._btCollisionConfiguration); this._btCollisionConfiguration = null; } _addPhysicsCollider(component, group, mask) { ILaya3D.Physics3D._bullet.btCollisionWorld_addCollisionObject(this._btCollisionWorld, component._btColliderObject, group, mask); } _removePhysicsCollider(component) { ILaya3D.Physics3D._bullet.btCollisionWorld_removeCollisionObject(this._btCollisionWorld, component._btColliderObject); } _addRigidBody(rigidBody, group, mask) { if (!this._btDiscreteDynamicsWorld) throw "Simulation:Cannot perform this action when the physics engine is set to CollisionsOnly"; ILaya3D.Physics3D._bullet.btDiscreteDynamicsWorld_addRigidBody(this._btCollisionWorld, rigidBody._btColliderObject, group, mask); } _removeRigidBody(rigidBody) { if (!this._btDiscreteDynamicsWorld) throw "Simulation:Cannot perform this action when the physics engine is set to CollisionsOnly"; ILaya3D.Physics3D._bullet.btDiscreteDynamicsWorld_removeRigidBody(this._btCollisionWorld, rigidBody._btColliderObject); } _addCharacter(character, group, mask) { if (!this._btDiscreteDynamicsWorld) throw "Simulation:Cannot perform this action when the physics engine is set to CollisionsOnly"; var bt = ILaya3D.Physics3D._bullet; bt.btCollisionWorld_addCollisionObject(this._btCollisionWorld, character._btColliderObject, group, mask); bt.btDynamicsWorld_addAction(this._btCollisionWorld, character._btKinematicCharacter); } _removeCharacter(character) { if (!this._btDiscreteDynamicsWorld) throw "Simulation:Cannot perform this action when the physics engine is set to CollisionsOnly"; var bt = ILaya3D.Physics3D._bullet; bt.btCollisionWorld_removeCollisionObject(this._btCollisionWorld, character._btColliderObject); bt.btDynamicsWorld_removeAction(this._btCollisionWorld, character._btKinematicCharacter); } raycastFromTo(from, to, out = null, collisonGroup = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER, collisionMask = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER) { var bt = ILaya3D.Physics3D._bullet; var rayResultCall = this._btClosestRayResultCallback; var rayFrom = PhysicsSimulation._btTempVector30; var rayTo = PhysicsSimulation._btTempVector31; bt.btVector3_setValue(rayFrom, -from.x, from.y, from.z); bt.btVector3_setValue(rayTo, -to.x, to.y, to.z); bt.ClosestRayResultCallback_set_m_rayFromWorld(rayResultCall, rayFrom); bt.ClosestRayResultCallback_set_m_rayToWorld(rayResultCall, rayTo); bt.RayResultCallback_set_m_collisionFilterGroup(rayResultCall, collisonGroup); bt.RayResultCallback_set_m_collisionFilterMask(rayResultCall, collisionMask); bt.RayResultCallback_set_m_collisionObject(rayResultCall, null); bt.RayResultCallback_set_m_closestHitFraction(rayResultCall, 1); bt.btCollisionWorld_rayTest(this._btCollisionWorld, rayFrom, rayTo, rayResultCall); if (bt.RayResultCallback_hasHit(rayResultCall)) { if (out) { out.succeeded = true; out.collider = PhysicsComponent._physicObjectsMap[bt.btCollisionObject_getUserIndex(bt.RayResultCallback_get_m_collisionObject(rayResultCall))]; out.hitFraction = bt.RayResultCallback_get_m_closestHitFraction(rayResultCall); var btPoint = bt.ClosestRayResultCallback_get_m_hitPointWorld(rayResultCall); var point = out.point; point.x = -bt.btVector3_x(btPoint); point.y = bt.btVector3_y(btPoint); point.z = bt.btVector3_z(btPoint); var btNormal = bt.ClosestRayResultCallback_get_m_hitNormalWorld(rayResultCall); var normal = out.normal; normal.x = -bt.btVector3_x(btNormal); normal.y = bt.btVector3_y(btNormal); normal.z = bt.btVector3_z(btNormal); } return true; } else { if (out) out.succeeded = false; return false; } } raycastAllFromTo(from, to, out, collisonGroup = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER, collisionMask = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER) { var bt = ILaya3D.Physics3D._bullet; var rayResultCall = this._btAllHitsRayResultCallback; var rayFrom = PhysicsSimulation._btTempVector30; var rayTo = PhysicsSimulation._btTempVector31; out.length = 0; bt.btVector3_setValue(rayFrom, -from.x, from.y, from.z); bt.btVector3_setValue(rayTo, -to.x, to.y, to.z); bt.AllHitsRayResultCallback_set_m_rayFromWorld(rayResultCall, rayFrom); bt.AllHitsRayResultCallback_set_m_rayToWorld(rayResultCall, rayTo); bt.RayResultCallback_set_m_collisionFilterGroup(rayResultCall, collisonGroup); bt.RayResultCallback_set_m_collisionFilterMask(rayResultCall, collisionMask); var collisionObjects = bt.AllHitsRayResultCallback_get_m_collisionObjects(rayResultCall); var btPoints = bt.AllHitsRayResultCallback_get_m_hitPointWorld(rayResultCall); var btNormals = bt.AllHitsRayResultCallback_get_m_hitNormalWorld(rayResultCall); var btFractions = bt.AllHitsRayResultCallback_get_m_hitFractions(rayResultCall); bt.tBtCollisionObjectArray_clear(collisionObjects); bt.tVector3Array_clear(btPoints); bt.tVector3Array_clear(btNormals); bt.tScalarArray_clear(btFractions); bt.btCollisionWorld_rayTest(this._btCollisionWorld, rayFrom, rayTo, rayResultCall); var count = bt.tBtCollisionObjectArray_size(collisionObjects); if (count > 0) { this._collisionsUtils.recoverAllHitResultsPool(); for (var i = 0; i < count; i++) { var hitResult = this._collisionsUtils.getHitResult(); out.push(hitResult); hitResult.succeeded = true; hitResult.collider = PhysicsComponent._physicObjectsMap[bt.btCollisionObject_getUserIndex(bt.tBtCollisionObjectArray_at(collisionObjects, i))]; hitResult.hitFraction = bt.tScalarArray_at(btFractions, i); var btPoint = bt.tVector3Array_at(btPoints, i); var pointE = hitResult.point; pointE.x = -bt.btVector3_x(btPoint); pointE.y = bt.btVector3_y(btPoint); pointE.z = bt.btVector3_z(btPoint); var btNormal = bt.tVector3Array_at(btNormals, i); var normal = hitResult.normal; normal.x = -bt.btVector3_x(btNormal); normal.y = bt.btVector3_y(btNormal); normal.z = bt.btVector3_z(btNormal); } return true; } else { return false; } } rayCast(ray, outHitResult = null, distance = 2147483647, collisonGroup = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER, collisionMask = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER) { var from = ray.origin; var to = PhysicsSimulation._tempVector30; Vector3.normalize(ray.direction, to); Vector3.scale(to, distance, to); Vector3.add(from, to, to); return this.raycastFromTo(from, to, outHitResult, collisonGroup, collisionMask); } rayCastAll(ray, out, distance = 2147483647, collisonGroup = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER, collisionMask = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER) { var from = ray.origin; var to = PhysicsSimulation._tempVector30; Vector3.normalize(ray.direction, to); Vector3.scale(to, distance, to); Vector3.add(from, to, to); return this.raycastAllFromTo(from, to, out, collisonGroup, collisionMask); } shapeCast(shape, fromPosition, toPosition, out = null, fromRotation = null, toRotation = null, collisonGroup = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER, collisionMask = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER, allowedCcdPenetration = 0.0) { var bt = ILaya3D.Physics3D._bullet; var convexResultCall = this._btClosestConvexResultCallback; var convexPosFrom = PhysicsSimulation._btTempVector30; var convexPosTo = PhysicsSimulation._btTempVector31; var convexRotFrom = PhysicsSimulation._btTempQuaternion0; var convexRotTo = PhysicsSimulation._btTempQuaternion1; var convexTransform = PhysicsSimulation._btTempTransform0; var convexTransTo = PhysicsSimulation._btTempTransform1; var sweepShape = shape._btShape; bt.btVector3_setValue(convexPosFrom, -fromPosition.x, fromPosition.y, fromPosition.z); bt.btVector3_setValue(convexPosTo, -toPosition.x, toPosition.y, toPosition.z); bt.ConvexResultCallback_set_m_collisionFilterGroup(convexResultCall, collisonGroup); bt.ConvexResultCallback_set_m_collisionFilterMask(convexResultCall, collisionMask); bt.btTransform_setOrigin(convexTransform, convexPosFrom); bt.btTransform_setOrigin(convexTransTo, convexPosTo); if (fromRotation) { bt.btQuaternion_setValue(convexRotFrom, -fromRotation.x, fromRotation.y, fromRotation.z, -fromRotation.w); bt.btTransform_setRotation(convexTransform, convexRotFrom); } else { bt.btTransform_setRotation(convexTransform, this._btDefaultQuaternion); } if (toRotation) { bt.btQuaternion_setValue(convexRotTo, -toRotation.x, toRotation.y, toRotation.z, -toRotation.w); bt.btTransform_setRotation(convexTransTo, convexRotTo); } else { bt.btTransform_setRotation(convexTransTo, this._btDefaultQuaternion); } bt.ClosestConvexResultCallback_set_m_hitCollisionObject(convexResultCall, null); bt.ConvexResultCallback_set_m_closestHitFraction(convexResultCall, 1); bt.btCollisionWorld_convexSweepTest(this._btCollisionWorld, sweepShape, convexTransform, convexTransTo, convexResultCall, allowedCcdPenetration); if (bt.ConvexResultCallback_hasHit(convexResultCall)) { if (out) { out.succeeded = true; out.collider = PhysicsComponent._physicObjectsMap[bt.btCollisionObject_getUserIndex(bt.ClosestConvexResultCallback_get_m_hitCollisionObject(convexResultCall))]; out.hitFraction = bt.ConvexResultCallback_get_m_closestHitFraction(convexResultCall); var btPoint = bt.ClosestConvexResultCallback_get_m_hitPointWorld(convexResultCall); var btNormal = bt.ClosestConvexResultCallback_get_m_hitNormalWorld(convexResultCall); var point = out.point; var normal = out.normal; point.x = -bt.btVector3_x(btPoint); point.y = bt.btVector3_y(btPoint); point.z = bt.btVector3_z(btPoint); normal.x = -bt.btVector3_x(btNormal); normal.y = bt.btVector3_y(btNormal); normal.z = bt.btVector3_z(btNormal); } return true; } else { if (out) out.succeeded = false; return false; } } shapeCastAll(shape, fromPosition, toPosition, out, fromRotation = null, toRotation = null, collisonGroup = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER, collisionMask = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER, allowedCcdPenetration = 0.0) { var bt = ILaya3D.Physics3D._bullet; var convexResultCall = this._btAllConvexResultCallback; var convexPosFrom = PhysicsSimulation._btTempVector30; var convexPosTo = PhysicsSimulation._btTempVector31; var convexRotFrom = PhysicsSimulation._btTempQuaternion0; var convexRotTo = PhysicsSimulation._btTempQuaternion1; var convexTransform = PhysicsSimulation._btTempTransform0; var convexTransTo = PhysicsSimulation._btTempTransform1; var sweepShape = shape._btShape; out.length = 0; bt.btVector3_setValue(convexPosFrom, -fromPosition.x, fromPosition.y, fromPosition.z); bt.btVector3_setValue(convexPosTo, -toPosition.x, toPosition.y, toPosition.z); bt.ConvexResultCallback_set_m_collisionFilterGroup(convexResultCall, collisonGroup); bt.ConvexResultCallback_set_m_collisionFilterMask(convexResultCall, collisionMask); bt.btTransform_setOrigin(convexTransform, convexPosFrom); bt.btTransform_setOrigin(convexTransTo, convexPosTo); if (fromRotation) { bt.btQuaternion_setValue(convexRotFrom, -fromRotation.x, fromRotation.y, fromRotation.z, -fromRotation.w); bt.btTransform_setRotation(convexTransform, convexRotFrom); } else { bt.btTransform_setRotation(convexTransform, this._btDefaultQuaternion); } if (toRotation) { bt.btQuaternion_setValue(convexRotTo, -toRotation.x, toRotation.y, toRotation.z, -toRotation.w); bt.btTransform_setRotation(convexTransTo, convexRotTo); } else { bt.btTransform_setRotation(convexTransTo, this._btDefaultQuaternion); } var collisionObjects = bt.AllConvexResultCallback_get_m_collisionObjects(convexResultCall); bt.tBtCollisionObjectArray_clear(collisionObjects); bt.btCollisionWorld_convexSweepTest(this._btCollisionWorld, sweepShape, convexTransform, convexTransTo, convexResultCall, allowedCcdPenetration); var count = bt.tBtCollisionObjectArray_size(collisionObjects); if (count > 0) { this._collisionsUtils.recoverAllHitResultsPool(); var btPoints = bt.AllConvexResultCallback_get_m_hitPointWorld(convexResultCall); var btNormals = bt.AllConvexResultCallback_get_m_hitNormalWorld(convexResultCall); var btFractions = bt.AllConvexResultCallback_get_m_hitFractions(convexResultCall); for (var i = 0; i < count; i++) { var hitResult = this._collisionsUtils.getHitResult(); out.push(hitResult); hitResult.succeeded = true; hitResult.collider = PhysicsComponent._physicObjectsMap[bt.btCollisionObject_getUserIndex(bt.tBtCollisionObjectArray_at(collisionObjects, i))]; hitResult.hitFraction = bt.tScalarArray_at(btFractions, i); var btPoint = bt.tVector3Array_at(btPoints, i); var point = hitResult.point; point.x = -bt.btVector3_x(btPoint); point.y = bt.btVector3_y(btPoint); point.z = bt.btVector3_z(btPoint); var btNormal = bt.tVector3Array_at(btNormals, i); var normal = hitResult.normal; normal.x = -bt.btVector3_x(btNormal); normal.y = bt.btVector3_y(btNormal); normal.z = bt.btVector3_z(btNormal); } return true; } else { return false; } } addConstraint(constraint, disableCollisionsBetweenLinkedBodies = false) { if (!this._btDiscreteDynamicsWorld) throw "Cannot perform this action when the physics engine is set to CollisionsOnly"; ILaya3D.Physics3D._bullet.btCollisionWorld_addConstraint(this._btDiscreteDynamicsWorld, constraint._btConstraint, disableCollisionsBetweenLinkedBodies); this._currentConstraint[constraint.id] = constraint; } removeConstraint(constraint) { if (!this._btDiscreteDynamicsWorld) throw "Cannot perform this action when the physics engine is set to CollisionsOnly"; ILaya3D.Physics3D._bullet.btCollisionWorld_removeConstraint(this._btDiscreteDynamicsWorld, constraint._btConstraint); delete this._currentConstraint[constraint.id]; } _updatePhysicsTransformFromRender() { var elements = this._physicsUpdateList.elements; for (var i = 0, n = this._physicsUpdateList.length; i < n; i++) { var physicCollider = elements[i]; physicCollider._derivePhysicsTransformation(false); physicCollider._inPhysicUpdateListIndex = -1; } this._physicsUpdateList.length = 0; } _updateCharacters() { for (var i = 0, n = this._characters.length; i < n; i++) { var character = this._characters[i]; character._updateTransformComponent(ILaya3D.Physics3D._bullet.btCollisionObject_getWorldTransform(character._btColliderObject)); } } _updateCollisions() { this._collisionsUtils.recoverAllContactPointsPool(); var previous = this._currentFrameCollisions; this._currentFrameCollisions = this._previousFrameCollisions; this._currentFrameCollisions.length = 0; this._previousFrameCollisions = previous; var loopCount = Laya.Stat.loopCount; var bt = ILaya3D.Physics3D._bullet; var numManifolds = bt.btDispatcher_getNumManifolds(this._btDispatcher); for (var i = 0; i < numManifolds; i++) { var contactManifold = bt.btDispatcher_getManifoldByIndexInternal(this._btDispatcher, i); var componentA = PhysicsComponent._physicObjectsMap[bt.btCollisionObject_getUserIndex(bt.btPersistentManifold_getBody0(contactManifold))]; var componentB = PhysicsComponent._physicObjectsMap[bt.btCollisionObject_getUserIndex(bt.btPersistentManifold_getBody1(contactManifold))]; var collision = null; var isFirstCollision; var contacts = null; var isTrigger = componentA.isTrigger || componentB.isTrigger; if (isTrigger && (componentA.owner._needProcessTriggers || componentB.owner._needProcessTriggers)) { var numContacts = bt.btPersistentManifold_getNumContacts(contactManifold); for (var j = 0; j < numContacts; j++) { var pt = bt.btPersistentManifold_getContactPoint(contactManifold, j); var distance = bt.btManifoldPoint_getDistance(pt); if (distance <= 0) { collision = this._collisionsUtils.getCollision(componentA, componentB); contacts = collision.contacts; isFirstCollision = collision._updateFrame !== loopCount; if (isFirstCollision) { collision._isTrigger = true; contacts.length = 0; } break; } } } else if (componentA.owner._needProcessCollisions || componentB.owner._needProcessCollisions) { if (componentA._enableProcessCollisions || componentB._enableProcessCollisions) { numContacts = bt.btPersistentManifold_getNumContacts(contactManifold); for (j = 0; j < numContacts; j++) { pt = bt.btPersistentManifold_getContactPoint(contactManifold, j); distance = bt.btManifoldPoint_getDistance(pt); if (distance <= 0) { var contactPoint = this._collisionsUtils.getContactPoints(); contactPoint.colliderA = componentA; contactPoint.colliderB = componentB; contactPoint.distance = distance; var btNormal = bt.btManifoldPoint_get_m_normalWorldOnB(pt); var normal = contactPoint.normal; normal.x = -bt.btVector3_x(btNormal); normal.y = bt.btVector3_y(btNormal); normal.z = bt.btVector3_z(btNormal); var btPostionA = bt.btManifoldPoint_get_m_positionWorldOnA(pt); var positionOnA = contactPoint.positionOnA; positionOnA.x = -bt.btVector3_x(btPostionA); positionOnA.y = bt.btVector3_y(btPostionA); positionOnA.z = bt.btVector3_z(btPostionA); var btPostionB = bt.btManifoldPoint_get_m_positionWorldOnB(pt); var positionOnB = contactPoint.positionOnB; positionOnB.x = -bt.btVector3_x(btPostionB); positionOnB.y = bt.btVector3_y(btPostionB); positionOnB.z = bt.btVector3_z(btPostionB); if (!collision) { collision = this._collisionsUtils.getCollision(componentA, componentB); contacts = collision.contacts; isFirstCollision = collision._updateFrame !== loopCount; if (isFirstCollision) { collision._isTrigger = false; contacts.length = 0; } } contacts.push(contactPoint); } } } } if (collision && isFirstCollision) { this._currentFrameCollisions.push(collision); collision._setUpdateFrame(loopCount); } } } _eventScripts() { var loopCount = Laya.Stat.loopCount; for (var i = 0, n = this._currentFrameCollisions.length; i < n; i++) { var curFrameCol = this._currentFrameCollisions[i]; var colliderA = curFrameCol._colliderA; var colliderB = curFrameCol._colliderB; if (colliderA.destroyed || colliderB.destroyed) continue; if (loopCount - curFrameCol._lastUpdateFrame === 1) { var ownerA = colliderA.owner; var scriptsA = ownerA._scripts; if (scriptsA) { if (curFrameCol._isTrigger) { if (ownerA._needProcessTriggers) { for (var j = 0, m = scriptsA.length; j < m; j++) scriptsA[j].onTriggerStay(colliderB); } } else { if (ownerA._needProcessCollisions) { for (j = 0, m = scriptsA.length; j < m; j++) { curFrameCol.other = colliderB; scriptsA[j].onCollisionStay(curFrameCol); } } } } var ownerB = colliderB.owner; var scriptsB = ownerB._scripts; if (scriptsB) { if (curFrameCol._isTrigger) { if (ownerB._needProcessTriggers) { for (j = 0, m = scriptsB.length; j < m; j++) scriptsB[j].onTriggerStay(colliderA); } } else { if (ownerB._needProcessCollisions) { for (j = 0, m = scriptsB.length; j < m; j++) { curFrameCol.other = colliderA; scriptsB[j].onCollisionStay(curFrameCol); } } } } } else { ownerA = colliderA.owner; scriptsA = ownerA._scripts; if (scriptsA) { if (curFrameCol._isTrigger) { if (ownerA._needProcessTriggers) { for (j = 0, m = scriptsA.length; j < m; j++) scriptsA[j].onTriggerEnter(colliderB); } } else { if (ownerA._needProcessCollisions) { for (j = 0, m = scriptsA.length; j < m; j++) { curFrameCol.other = colliderB; scriptsA[j].onCollisionEnter(curFrameCol); } } } } ownerB = colliderB.owner; scriptsB = ownerB._scripts; if (scriptsB) { if (curFrameCol._isTrigger) { if (ownerB._needProcessTriggers) { for (j = 0, m = scriptsB.length; j < m; j++) scriptsB[j].onTriggerEnter(colliderA); } } else { if (ownerB._needProcessCollisions) { for (j = 0, m = scriptsB.length; j < m; j++) { curFrameCol.other = colliderA; scriptsB[j].onCollisionEnter(curFrameCol); } } } } } } for (i = 0, n = this._previousFrameCollisions.length; i < n; i++) { var preFrameCol = this._previousFrameCollisions[i]; var preColliderA = preFrameCol._colliderA; var preColliderB = preFrameCol._colliderB; if (preColliderA.destroyed || preColliderB.destroyed) continue; if (loopCount - preFrameCol._updateFrame === 1) { this._collisionsUtils.recoverCollision(preFrameCol); ownerA = preColliderA.owner; scriptsA = ownerA._scripts; if (scriptsA) { if (preFrameCol._isTrigger) { if (ownerA._needProcessTriggers) { for (j = 0, m = scriptsA.length; j < m; j++) scriptsA[j].onTriggerExit(preColliderB); } } else { if (ownerA._needProcessCollisions) { for (j = 0, m = scriptsA.length; j < m; j++) { preFrameCol.other = preColliderB; scriptsA[j].onCollisionExit(preFrameCol); } } } } ownerB = preColliderB.owner; scriptsB = ownerB._scripts; if (scriptsB) { if (preFrameCol._isTrigger) { if (ownerB._needProcessTriggers) { for (j = 0, m = scriptsB.length; j < m; j++) scriptsB[j].onTriggerExit(preColliderA); } } else { if (ownerB._needProcessCollisions) { for (j = 0, m = scriptsB.length; j < m; j++) { preFrameCol.other = preColliderA; scriptsB[j].onCollisionExit(preFrameCol); } } } } } } for (var id in this._currentConstraint) { var constraintObj = this._currentConstraint[id]; var scripts = constraintObj.owner._scripts; if (constraintObj.enabled && constraintObj._isBreakConstrained() && (!!scripts)) { if (scripts.length != 0) { for (i = 0, n = scripts.length; i < n; i++) { scripts[i].onJointBreak(); } } } } } clearForces() { if (!this._btDiscreteDynamicsWorld) throw "Cannot perform this action when the physics engine is set to CollisionsOnly"; ILaya3D.Physics3D._bullet.btDiscreteDynamicsWorld_clearForces(this._btDiscreteDynamicsWorld); } } PhysicsSimulation.PHYSICSENGINEFLAGS_NONE = 0x0; PhysicsSimulation.PHYSICSENGINEFLAGS_COLLISIONSONLY = 0x1; PhysicsSimulation.PHYSICSENGINEFLAGS_SOFTBODYSUPPORT = 0x2; PhysicsSimulation.PHYSICSENGINEFLAGS_MULTITHREADED = 0x4; PhysicsSimulation.PHYSICSENGINEFLAGS_USEHARDWAREWHENPOSSIBLE = 0x8; PhysicsSimulation.SOLVERMODE_RANDMIZE_ORDER = 1; PhysicsSimulation.SOLVERMODE_FRICTION_SEPARATE = 2; PhysicsSimulation.SOLVERMODE_USE_WARMSTARTING = 4; PhysicsSimulation.SOLVERMODE_USE_2_FRICTION_DIRECTIONS = 16; PhysicsSimulation.SOLVERMODE_ENABLE_FRICTION_DIRECTION_CACHING = 32; PhysicsSimulation.SOLVERMODE_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION = 64; PhysicsSimulation.SOLVERMODE_CACHE_FRIENDLY = 128; PhysicsSimulation.SOLVERMODE_SIMD = 256; PhysicsSimulation.SOLVERMODE_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS = 512; PhysicsSimulation.SOLVERMODE_ALLOW_ZERO_LENGTH_FRICTION_DIRECTIONS = 1024; PhysicsSimulation._tempVector30 = new Vector3(); PhysicsSimulation.disableSimulation = false; class TextureGenerator { constructor() { } static lightAttenTexture(x, y, maxX, maxY, index, data) { var sqrRange = x / maxX; var atten = 1.0 / (1.0 + 25.0 * sqrRange); if (sqrRange >= 0.64) { if (sqrRange > 1.0) { atten = 0; } else { atten *= 1 - (sqrRange - 0.64) / (1 - 0.64); } } data[index] = Math.floor(atten * 255.0 + 0.5); } static haloTexture(x, y, maxX, maxY, index, data) { maxX >>= 1; maxY >>= 1; var xFac = (x - maxX) / maxX; var yFac = (y - maxY) / maxY; var sqrRange = xFac * xFac + yFac * yFac; if (sqrRange > 1.0) { sqrRange = 1.0; } data[index] = Math.floor((1.0 - sqrRange) * 255.0 + 0.5); } static _generateTexture2D(texture, textureWidth, textureHeight, func) { var index = 0; var size = 0; switch (texture.format) { case Laya.TextureFormat.R8G8B8: size = 3; break; case Laya.TextureFormat.R8G8B8A8: size = 4; break; case Laya.TextureFormat.Alpha8: size = 1; break; default: throw "GeneratedTexture._generateTexture: unkonw texture format."; } var data = new Uint8Array(textureWidth * textureHeight * size); for (var y = 0; y < textureHeight; y++) { for (var x = 0; x < textureWidth; x++) { func(x, y, textureWidth, textureHeight, index, data); index += size; } } texture.setPixels(data); } } class Utils3D { static _createFloatTextureBuffer(width, height) { var floatTex = new Laya.Texture2D(width, height, Laya.TextureFormat.R32G32B32A32, false, false); floatTex.filterMode = Laya.FilterMode.Point; floatTex.wrapModeU = Laya.WarpMode.Clamp; floatTex.wrapModeV = Laya.WarpMode.Clamp; floatTex.anisoLevel = 0; return floatTex; } static _convertToLayaVec3(bVector, out, inverseX) { var bullet = ILaya3D.Physics3D._bullet; out.x = inverseX ? -bullet.btVector3_x(bVector) : bullet.btVector3_x(bVector); out.y = bullet.btVector3_y(bVector); out.z = bullet.btVector3_z(bVector); } static _convertToBulletVec3(lVector, out, inverseX) { ILaya3D.Physics3D._bullet.btVector3_setValue(out, inverseX ? -lVector.x : lVector.x, lVector.y, lVector.z); } static _rotationTransformScaleSkinAnimation(tx, ty, tz, qx, qy, qz, qw, sx, sy, sz, outArray, outOffset) { var re = Utils3D._tempArray16_0; var se = Utils3D._tempArray16_1; var tse = Utils3D._tempArray16_2; var x2 = qx + qx; var y2 = qy + qy; var z2 = qz + qz; var xx = qx * x2; var yx = qy * x2; var yy = qy * y2; var zx = qz * x2; var zy = qz * y2; var zz = qz * z2; var wx = qw * x2; var wy = qw * y2; var wz = qw * z2; re[15] = 1; re[0] = 1 - yy - zz; re[1] = yx + wz; re[2] = zx - wy; re[4] = yx - wz; re[5] = 1 - xx - zz; re[6] = zy + wx; re[8] = zx + wy; re[9] = zy - wx; re[10] = 1 - xx - yy; se[15] = 1; se[0] = sx; se[5] = sy; se[10] = sz; var i, ai0, ai1, ai2, ai3; for (i = 0; i < 4; i++) { ai0 = re[i]; ai1 = re[i + 4]; ai2 = re[i + 8]; ai3 = re[i + 12]; tse[i] = ai0; tse[i + 4] = ai1; tse[i + 8] = ai2; tse[i + 12] = ai0 * tx + ai1 * ty + ai2 * tz + ai3; } for (i = 0; i < 4; i++) { ai0 = tse[i]; ai1 = tse[i + 4]; ai2 = tse[i + 8]; ai3 = tse[i + 12]; outArray[i + outOffset] = ai0 * se[0] + ai1 * se[1] + ai2 * se[2] + ai3 * se[3]; outArray[i + outOffset + 4] = ai0 * se[4] + ai1 * se[5] + ai2 * se[6] + ai3 * se[7]; outArray[i + outOffset + 8] = ai0 * se[8] + ai1 * se[9] + ai2 * se[10] + ai3 * se[11]; outArray[i + outOffset + 12] = ai0 * se[12] + ai1 * se[13] + ai2 * se[14] + ai3 * se[15]; } } static _computeBoneAndAnimationDatasByBindPoseMatrxix(bones, curData, inverGlobalBindPose, outBonesDatas, outAnimationDatas, boneIndexToMesh) { var offset = 0; var matOffset = 0; var i; var parentOffset; var boneLength = bones.length; for (i = 0; i < boneLength; offset += bones[i].keyframeWidth, matOffset += 16, i++) { Utils3D._rotationTransformScaleSkinAnimation(curData[offset + 0], curData[offset + 1], curData[offset + 2], curData[offset + 3], curData[offset + 4], curData[offset + 5], curData[offset + 6], curData[offset + 7], curData[offset + 8], curData[offset + 9], outBonesDatas, matOffset); if (i != 0) { parentOffset = bones[i].parentIndex * 16; Utils3D.mulMatrixByArray(outBonesDatas, parentOffset, outBonesDatas, matOffset, outBonesDatas, matOffset); } } var n = inverGlobalBindPose.length; for (i = 0; i < n; i++) { Utils3D.mulMatrixByArrayAndMatrixFast(outBonesDatas, boneIndexToMesh[i] * 16, inverGlobalBindPose[i], outAnimationDatas, i * 16); } } static _computeAnimationDatasByArrayAndMatrixFast(inverGlobalBindPose, bonesDatas, outAnimationDatas, boneIndexToMesh) { for (var i = 0, n = inverGlobalBindPose.length; i < n; i++) Utils3D.mulMatrixByArrayAndMatrixFast(bonesDatas, boneIndexToMesh[i] * 16, inverGlobalBindPose[i], outAnimationDatas, i * 16); } static _computeBoneAndAnimationDatasByBindPoseMatrxixOld(bones, curData, inverGlobalBindPose, outBonesDatas, outAnimationDatas) { var offset = 0; var matOffset = 0; var i; var parentOffset; var boneLength = bones.length; for (i = 0; i < boneLength; offset += bones[i].keyframeWidth, matOffset += 16, i++) { Utils3D._rotationTransformScaleSkinAnimation(curData[offset + 7], curData[offset + 8], curData[offset + 9], curData[offset + 3], curData[offset + 4], curData[offset + 5], curData[offset + 6], curData[offset + 0], curData[offset + 1], curData[offset + 2], outBonesDatas, matOffset); if (i != 0) { parentOffset = bones[i].parentIndex * 16; Utils3D.mulMatrixByArray(outBonesDatas, parentOffset, outBonesDatas, matOffset, outBonesDatas, matOffset); } } var n = inverGlobalBindPose.length; for (i = 0; i < n; i++) { var arrayOffset = i * 16; Utils3D.mulMatrixByArrayAndMatrixFast(outBonesDatas, arrayOffset, inverGlobalBindPose[i], outAnimationDatas, arrayOffset); } } static _computeAnimationDatasByArrayAndMatrixFastOld(inverGlobalBindPose, bonesDatas, outAnimationDatas) { var n = inverGlobalBindPose.length; for (var i = 0; i < n; i++) { var arrayOffset = i * 16; Utils3D.mulMatrixByArrayAndMatrixFast(bonesDatas, arrayOffset, inverGlobalBindPose[i], outAnimationDatas, arrayOffset); } } static _computeRootAnimationData(bones, curData, animationDatas) { for (var i = 0, offset = 0, matOffset = 0, boneLength = bones.length; i < boneLength; offset += bones[i].keyframeWidth, matOffset += 16, i++) Utils3D.createAffineTransformationArray(curData[offset + 0], curData[offset + 1], curData[offset + 2], curData[offset + 3], curData[offset + 4], curData[offset + 5], curData[offset + 6], curData[offset + 7], curData[offset + 8], curData[offset + 9], animationDatas, matOffset); } static transformVector3ArrayByQuat(sourceArray, sourceOffset, rotation, outArray, outOffset) { var x = sourceArray[sourceOffset], y = sourceArray[sourceOffset + 1], z = sourceArray[sourceOffset + 2], qx = rotation.x, qy = rotation.y, qz = rotation.z, qw = rotation.w, ix = qw * x + qy * z - qz * y, iy = qw * y + qz * x - qx * z, iz = qw * z + qx * y - qy * x, iw = -qx * x - qy * y - qz * z; outArray[outOffset] = ix * qw + iw * -qx + iy * -qz - iz * -qy; outArray[outOffset + 1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; outArray[outOffset + 2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; } static mulMatrixByArray(leftArray, leftOffset, rightArray, rightOffset, outArray, outOffset) { var i, ai0, ai1, ai2, ai3; if (outArray === rightArray) { rightArray = Utils3D._tempArray16_3; for (i = 0; i < 16; ++i) { rightArray[i] = outArray[outOffset + i]; } rightOffset = 0; } for (i = 0; i < 4; i++) { ai0 = leftArray[leftOffset + i]; ai1 = leftArray[leftOffset + i + 4]; ai2 = leftArray[leftOffset + i + 8]; ai3 = leftArray[leftOffset + i + 12]; outArray[outOffset + i] = ai0 * rightArray[rightOffset + 0] + ai1 * rightArray[rightOffset + 1] + ai2 * rightArray[rightOffset + 2] + ai3 * rightArray[rightOffset + 3]; outArray[outOffset + i + 4] = ai0 * rightArray[rightOffset + 4] + ai1 * rightArray[rightOffset + 5] + ai2 * rightArray[rightOffset + 6] + ai3 * rightArray[rightOffset + 7]; outArray[outOffset + i + 8] = ai0 * rightArray[rightOffset + 8] + ai1 * rightArray[rightOffset + 9] + ai2 * rightArray[rightOffset + 10] + ai3 * rightArray[rightOffset + 11]; outArray[outOffset + i + 12] = ai0 * rightArray[rightOffset + 12] + ai1 * rightArray[rightOffset + 13] + ai2 * rightArray[rightOffset + 14] + ai3 * rightArray[rightOffset + 15]; } } static mulMatrixByArrayFast(leftArray, leftOffset, rightArray, rightOffset, outArray, outOffset) { var i, ai0, ai1, ai2, ai3; for (i = 0; i < 4; i++) { ai0 = leftArray[leftOffset + i]; ai1 = leftArray[leftOffset + i + 4]; ai2 = leftArray[leftOffset + i + 8]; ai3 = leftArray[leftOffset + i + 12]; outArray[outOffset + i] = ai0 * rightArray[rightOffset + 0] + ai1 * rightArray[rightOffset + 1] + ai2 * rightArray[rightOffset + 2] + ai3 * rightArray[rightOffset + 3]; outArray[outOffset + i + 4] = ai0 * rightArray[rightOffset + 4] + ai1 * rightArray[rightOffset + 5] + ai2 * rightArray[rightOffset + 6] + ai3 * rightArray[rightOffset + 7]; outArray[outOffset + i + 8] = ai0 * rightArray[rightOffset + 8] + ai1 * rightArray[rightOffset + 9] + ai2 * rightArray[rightOffset + 10] + ai3 * rightArray[rightOffset + 11]; outArray[outOffset + i + 12] = ai0 * rightArray[rightOffset + 12] + ai1 * rightArray[rightOffset + 13] + ai2 * rightArray[rightOffset + 14] + ai3 * rightArray[rightOffset + 15]; } } static mulMatrixByArrayAndMatrixFast(leftArray, leftOffset, rightMatrix, outArray, outOffset) { var i, ai0, ai1, ai2, ai3; var rightMatrixE = rightMatrix.elements; var m11 = rightMatrixE[0], m12 = rightMatrixE[1], m13 = rightMatrixE[2], m14 = rightMatrixE[3]; var m21 = rightMatrixE[4], m22 = rightMatrixE[5], m23 = rightMatrixE[6], m24 = rightMatrixE[7]; var m31 = rightMatrixE[8], m32 = rightMatrixE[9], m33 = rightMatrixE[10], m34 = rightMatrixE[11]; var m41 = rightMatrixE[12], m42 = rightMatrixE[13], m43 = rightMatrixE[14], m44 = rightMatrixE[15]; var ai0LeftOffset = leftOffset; var ai1LeftOffset = leftOffset + 4; var ai2LeftOffset = leftOffset + 8; var ai3LeftOffset = leftOffset + 12; var ai0OutOffset = outOffset; var ai1OutOffset = outOffset + 4; var ai2OutOffset = outOffset + 8; var ai3OutOffset = outOffset + 12; for (i = 0; i < 4; i++) { ai0 = leftArray[ai0LeftOffset + i]; ai1 = leftArray[ai1LeftOffset + i]; ai2 = leftArray[ai2LeftOffset + i]; ai3 = leftArray[ai3LeftOffset + i]; outArray[ai0OutOffset + i] = ai0 * m11 + ai1 * m12 + ai2 * m13 + ai3 * m14; outArray[ai1OutOffset + i] = ai0 * m21 + ai1 * m22 + ai2 * m23 + ai3 * m24; outArray[ai2OutOffset + i] = ai0 * m31 + ai1 * m32 + ai2 * m33 + ai3 * m34; outArray[ai3OutOffset + i] = ai0 * m41 + ai1 * m42 + ai2 * m43 + ai3 * m44; } } static createAffineTransformationArray(tX, tY, tZ, rX, rY, rZ, rW, sX, sY, sZ, outArray, outOffset) { var x2 = rX + rX, y2 = rY + rY, z2 = rZ + rZ; var xx = rX * x2, xy = rX * y2, xz = rX * z2, yy = rY * y2, yz = rY * z2, zz = rZ * z2; var wx = rW * x2, wy = rW * y2, wz = rW * z2; outArray[outOffset + 0] = (1 - (yy + zz)) * sX; outArray[outOffset + 1] = (xy + wz) * sX; outArray[outOffset + 2] = (xz - wy) * sX; outArray[outOffset + 3] = 0; outArray[outOffset + 4] = (xy - wz) * sY; outArray[outOffset + 5] = (1 - (xx + zz)) * sY; outArray[outOffset + 6] = (yz + wx) * sY; outArray[outOffset + 7] = 0; outArray[outOffset + 8] = (xz + wy) * sZ; outArray[outOffset + 9] = (yz - wx) * sZ; outArray[outOffset + 10] = (1 - (xx + yy)) * sZ; outArray[outOffset + 11] = 0; outArray[outOffset + 12] = tX; outArray[outOffset + 13] = tY; outArray[outOffset + 14] = tZ; outArray[outOffset + 15] = 1; } static transformVector3ArrayToVector3ArrayCoordinate(source, sourceOffset, transform, result, resultOffset) { var coordinateX = source[sourceOffset + 0]; var coordinateY = source[sourceOffset + 1]; var coordinateZ = source[sourceOffset + 2]; var transformElem = transform.elements; var w = ((coordinateX * transformElem[3]) + (coordinateY * transformElem[7]) + (coordinateZ * transformElem[11]) + transformElem[15]); result[resultOffset] = (coordinateX * transformElem[0]) + (coordinateY * transformElem[4]) + (coordinateZ * transformElem[8]) + transformElem[12] / w; result[resultOffset + 1] = (coordinateX * transformElem[1]) + (coordinateY * transformElem[5]) + (coordinateZ * transformElem[9]) + transformElem[13] / w; result[resultOffset + 2] = (coordinateX * transformElem[2]) + (coordinateY * transformElem[6]) + (coordinateZ * transformElem[10]) + transformElem[14] / w; } static transformVector3ArrayToVector3ArrayNormal(source, sourceOffset, transform, result, resultOffset) { var coordinateX = source[sourceOffset + 0]; var coordinateY = source[sourceOffset + 1]; var coordinateZ = source[sourceOffset + 2]; var transformElem = transform.elements; result[resultOffset] = coordinateX * transformElem[0] + coordinateY * transformElem[4] + coordinateZ * transformElem[8]; result[resultOffset + 1] = coordinateX * transformElem[1] + coordinateY * transformElem[5] + coordinateZ * transformElem[9]; result[resultOffset + 2] = coordinateX * transformElem[2] + coordinateY * transformElem[6] + coordinateZ * transformElem[10]; } static transformLightingMapTexcoordArray(source, sourceOffset, lightingMapScaleOffset, result, resultOffset) { result[resultOffset + 0] = source[sourceOffset + 0] * lightingMapScaleOffset.x + lightingMapScaleOffset.z; result[resultOffset + 1] = 1.0 - ((1.0 - source[sourceOffset + 1]) * lightingMapScaleOffset.y + lightingMapScaleOffset.w); } static getURLVerion(url) { var index = url.indexOf("?"); return index >= 0 ? url.substr(index) : null; } static _createAffineTransformationArray(trans, rot, scale, outE) { var x = rot.x, y = rot.y, z = rot.z, w = rot.w, x2 = x + x, y2 = y + y, z2 = z + z; var xx = x * x2, xy = x * y2, xz = x * z2, yy = y * y2, yz = y * z2, zz = z * z2; var wx = w * x2, wy = w * y2, wz = w * z2, sx = scale.x, sy = scale.y, sz = scale.z; outE[0] = (1 - (yy + zz)) * sx; outE[1] = (xy + wz) * sx; outE[2] = (xz - wy) * sx; outE[3] = 0; outE[4] = (xy - wz) * sy; outE[5] = (1 - (xx + zz)) * sy; outE[6] = (yz + wx) * sy; outE[7] = 0; outE[8] = (xz + wy) * sz; outE[9] = (yz - wx) * sz; outE[10] = (1 - (xx + yy)) * sz; outE[11] = 0; outE[12] = trans.x; outE[13] = trans.y; outE[14] = trans.z; outE[15] = 1; } static _mulMatrixArray(left, right, rightOffset, outArray, outOffset) { var l = right; var r = left; var e = outArray; var l11 = l[rightOffset], l12 = l[rightOffset + 1], l13 = l[rightOffset + 2], l14 = l[rightOffset + 3]; var l21 = l[rightOffset + 4], l22 = l[rightOffset + 5], l23 = l[rightOffset + 6], l24 = l[rightOffset + 7]; var l31 = l[rightOffset + 8], l32 = l[rightOffset + 9], l33 = l[rightOffset + 10], l34 = l[rightOffset + 11]; var l41 = l[rightOffset + 12], l42 = l[rightOffset + 13], l43 = l[rightOffset + 14], l44 = l[rightOffset + 15]; var r11 = r[0], r12 = r[1], r13 = r[2], r14 = r[3]; var r21 = r[4], r22 = r[5], r23 = r[6], r24 = r[7]; var r31 = r[8], r32 = r[9], r33 = r[10], r34 = r[11]; var r41 = r[12], r42 = r[13], r43 = r[14], r44 = r[15]; e[outOffset] = (l11 * r11) + (l12 * r21) + (l13 * r31) + (l14 * r41); e[outOffset + 1] = (l11 * r12) + (l12 * r22) + (l13 * r32) + (l14 * r42); e[outOffset + 2] = (l11 * r13) + (l12 * r23) + (l13 * r33) + (l14 * r43); e[outOffset + 3] = (l11 * r14) + (l12 * r24) + (l13 * r34) + (l14 * r44); e[outOffset + 4] = (l21 * r11) + (l22 * r21) + (l23 * r31) + (l24 * r41); e[outOffset + 5] = (l21 * r12) + (l22 * r22) + (l23 * r32) + (l24 * r42); e[outOffset + 6] = (l21 * r13) + (l22 * r23) + (l23 * r33) + (l24 * r43); e[outOffset + 7] = (l21 * r14) + (l22 * r24) + (l23 * r34) + (l24 * r44); e[outOffset + 8] = (l31 * r11) + (l32 * r21) + (l33 * r31) + (l34 * r41); e[outOffset + 9] = (l31 * r12) + (l32 * r22) + (l33 * r32) + (l34 * r42); e[outOffset + 10] = (l31 * r13) + (l32 * r23) + (l33 * r33) + (l34 * r43); e[outOffset + 11] = (l31 * r14) + (l32 * r24) + (l33 * r34) + (l34 * r44); e[outOffset + 12] = (l41 * r11) + (l42 * r21) + (l43 * r31) + (l44 * r41); e[outOffset + 13] = (l41 * r12) + (l42 * r22) + (l43 * r32) + (l44 * r42); e[outOffset + 14] = (l41 * r13) + (l42 * r23) + (l43 * r33) + (l44 * r43); e[outOffset + 15] = (l41 * r14) + (l42 * r24) + (l43 * r34) + (l44 * r44); } static arcTanAngle(x, y) { if (x == 0) { if (y == 1) return Math.PI / 2; return -Math.PI / 2; } if (x > 0) return Math.atan(y / x); if (x < 0) { if (y > 0) return Math.atan(y / x) + Math.PI; return Math.atan(y / x) - Math.PI; } return 0; } static angleTo(from, location, angle) { Vector3.subtract(location, from, Quaternion.TEMPVector30); Vector3.normalize(Quaternion.TEMPVector30, Quaternion.TEMPVector30); angle.x = Math.asin(Quaternion.TEMPVector30.y); angle.y = Utils3D.arcTanAngle(-Quaternion.TEMPVector30.z, -Quaternion.TEMPVector30.x); } static transformQuat(source, rotation, out) { var re = rotation; var x = source.x, y = source.y, z = source.z, qx = re[0], qy = re[1], qz = re[2], qw = re[3], ix = qw * x + qy * z - qz * y, iy = qw * y + qz * x - qx * z, iz = qw * z + qx * y - qy * x, iw = -qx * x - qy * y - qz * z; out.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; out.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; out.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; } static quaternionWeight(f, weight, e) { e.x = f.x * weight; e.y = f.y * weight; e.z = f.z * weight; e.w = f.w; } static quaternionConjugate(value, result) { result.x = -value.x; result.y = -value.y; result.z = -value.z; result.w = value.w; } static scaleWeight(s, w, out) { var sX = s.x, sY = s.y, sZ = s.z; out.x = sX > 0 ? Math.pow(Math.abs(sX), w) : -Math.pow(Math.abs(sX), w); out.y = sY > 0 ? Math.pow(Math.abs(sY), w) : -Math.pow(Math.abs(sY), w); out.z = sZ > 0 ? Math.pow(Math.abs(sZ), w) : -Math.pow(Math.abs(sZ), w); } static scaleBlend(sa, sb, w, out) { var saw = Utils3D._tempVector3_0; var sbw = Utils3D._tempVector3_1; Utils3D.scaleWeight(sa, 1.0 - w, saw); Utils3D.scaleWeight(sb, w, sbw); var sng = w > 0.5 ? sb : sa; out.x = sng.x > 0 ? Math.abs(saw.x * sbw.x) : -Math.abs(saw.x * sbw.x); out.y = sng.y > 0 ? Math.abs(saw.y * sbw.y) : -Math.abs(saw.y * sbw.y); out.z = sng.z > 0 ? Math.abs(saw.z * sbw.z) : -Math.abs(saw.z * sbw.z); } static matrix4x4MultiplyFFF(a, b, e) { var i, ai0, ai1, ai2, ai3; if (e === b) { b = new Float32Array(16); for (i = 0; i < 16; ++i) { b[i] = e[i]; } } var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; var b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7]; var b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11]; var b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15]; for (i = 0; i < 4; i++) { ai0 = a[i]; ai1 = a[i + 4]; ai2 = a[i + 8]; ai3 = a[i + 12]; e[i] = ai0 * b0 + ai1 * b1 + ai2 * b2 + ai3 * b3; e[i + 4] = ai0 * b4 + ai1 * b5 + ai2 * b6 + ai3 * b7; e[i + 8] = ai0 * b8 + ai1 * b9 + ai2 * b10 + ai3 * b11; e[i + 12] = ai0 * b12 + ai1 * b13 + ai2 * b14 + ai3 * b15; } } static matrix4x4MultiplyFFFForNative(a, b, e) { Laya.LayaGL.instance.matrix4x4Multiply(a, b, e); } static matrix4x4MultiplyMFM(left, right, out) { Utils3D.matrix4x4MultiplyFFF(left.elements, right, out.elements); } static _buildTexture2D(width, height, format, colorFunc, mipmaps = false) { var texture = new Laya.Texture2D(width, height, format, mipmaps, true); texture.anisoLevel = 1; texture.filterMode = Laya.FilterMode.Point; TextureGenerator._generateTexture2D(texture, width, height, colorFunc); return texture; } static _drawBound(debugLine, boundBox, color) { if (debugLine.lineCount + 12 > debugLine.maxLineCount) debugLine.maxLineCount += 12; var start = Utils3D._tempVector3_0; var end = Utils3D._tempVector3_1; var min = boundBox.min; var max = boundBox.max; start.setValue(min.x, min.y, min.z); end.setValue(max.x, min.y, min.z); debugLine.addLine(start, end, color, color); start.setValue(min.x, min.y, min.z); end.setValue(min.x, min.y, max.z); debugLine.addLine(start, end, color, color); start.setValue(max.x, min.y, min.z); end.setValue(max.x, min.y, max.z); debugLine.addLine(start, end, color, color); start.setValue(min.x, min.y, max.z); end.setValue(max.x, min.y, max.z); debugLine.addLine(start, end, color, color); start.setValue(min.x, min.y, min.z); end.setValue(min.x, max.y, min.z); debugLine.addLine(start, end, color, color); start.setValue(min.x, min.y, max.z); end.setValue(min.x, max.y, max.z); debugLine.addLine(start, end, color, color); start.setValue(max.x, min.y, min.z); end.setValue(max.x, max.y, min.z); debugLine.addLine(start, end, color, color); start.setValue(max.x, min.y, max.z); end.setValue(max.x, max.y, max.z); debugLine.addLine(start, end, color, color); start.setValue(min.x, max.y, min.z); end.setValue(max.x, max.y, min.z); debugLine.addLine(start, end, color, color); start.setValue(min.x, max.y, min.z); end.setValue(min.x, max.y, max.z); debugLine.addLine(start, end, color, color); start.setValue(max.x, max.y, min.z); end.setValue(max.x, max.y, max.z); debugLine.addLine(start, end, color, color); start.setValue(min.x, max.y, max.z); end.setValue(max.x, max.y, max.z); debugLine.addLine(start, end, color, color); } static _getHierarchyPath(rootSprite, checkSprite, path) { path.length = 0; var sprite = checkSprite; while (sprite !== rootSprite) { var parent = sprite._parent; if (parent) path.push(parent.getChildIndex(sprite)); else return null; sprite = parent; } return path; } static _getNodeByHierarchyPath(rootSprite, invPath) { var sprite = rootSprite; for (var i = invPath.length - 1; i >= 0; i--) { sprite = sprite.getChildAt(invPath[i]); } return sprite; } } Utils3D._tempVector3_0 = new Vector3(); Utils3D._tempVector3_1 = new Vector3(); Utils3D._tempArray16_0 = new Float32Array(16); Utils3D._tempArray16_1 = new Float32Array(16); Utils3D._tempArray16_2 = new Float32Array(16); Utils3D._tempArray16_3 = new Float32Array(16); Utils3D._compIdToNode = new Object(); class CharacterController extends PhysicsComponent { constructor(stepheight = 0.1, upAxis = null, collisionGroup = Physics3DUtils.COLLISIONFILTERGROUP_DEFAULTFILTER, canCollideWith = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER) { super(collisionGroup, canCollideWith); this._upAxis = new Vector3(0, 1, 0); this._maxSlope = 45.0; this._jumpSpeed = 10.0; this._fallSpeed = 55.0; this._gravity = new Vector3(0, -9.8 * 3, 0); this._btKinematicCharacter = null; this._stepHeight = stepheight; (upAxis) && (this._upAxis = upAxis); this._controlBySimulation = true; } static __init__() { CharacterController._btTempVector30 = ILaya3D.Physics3D._bullet.btVector3_create(0, 0, 0); } get fallSpeed() { return this._fallSpeed; } set fallSpeed(value) { this._fallSpeed = value; ILaya3D.Physics3D._bullet.btKinematicCharacterController_setFallSpeed(this._btKinematicCharacter, value); } get jumpSpeed() { return this._jumpSpeed; } set jumpSpeed(value) { this._jumpSpeed = value; ILaya3D.Physics3D._bullet.btKinematicCharacterController_setJumpSpeed(this._btKinematicCharacter, value); } get gravity() { return this._gravity; } set gravity(value) { this._gravity = value; var bt = ILaya3D.Physics3D._bullet; var btGravity = CharacterController._btTempVector30; bt.btVector3_setValue(btGravity, -value.x, value.y, value.z); bt.btKinematicCharacterController_setGravity(this._btKinematicCharacter, btGravity); } get maxSlope() { return this._maxSlope; } set maxSlope(value) { this._maxSlope = value; ILaya3D.Physics3D._bullet.btKinematicCharacterController_setMaxSlope(this._btKinematicCharacter, (value / 180) * Math.PI); } get isGrounded() { return ILaya3D.Physics3D._bullet.btKinematicCharacterController_onGround(this._btKinematicCharacter); } get stepHeight() { return this._stepHeight; } set stepHeight(value) { this._stepHeight = value; ILaya3D.Physics3D._bullet.btKinematicCharacterController_setStepHeight(this._btKinematicCharacter, value); } get upAxis() { return this._upAxis; } set upAxis(value) { this._upAxis = value; var btUpAxis = CharacterController._btTempVector30; Utils3D._convertToBulletVec3(value, btUpAxis, false); ILaya3D.Physics3D._bullet.btKinematicCharacterController_setUp(this._btKinematicCharacter, btUpAxis); } _constructCharacter() { var bt = ILaya3D.Physics3D._bullet; if (this._btKinematicCharacter) bt.btKinematicCharacterController_destroy(this._btKinematicCharacter); var btUpAxis = CharacterController._btTempVector30; bt.btVector3_setValue(btUpAxis, this._upAxis.x, this._upAxis.y, this._upAxis.z); this._btKinematicCharacter = bt.btKinematicCharacterController_create(this._btColliderObject, this._colliderShape._btShape, this._stepHeight, btUpAxis); this.fallSpeed = this._fallSpeed; this.maxSlope = this._maxSlope; this.jumpSpeed = this._jumpSpeed; this.gravity = this._gravity; } _onShapeChange(colShape) { super._onShapeChange(colShape); this._constructCharacter(); } _onAdded() { var bt = ILaya3D.Physics3D._bullet; var ghostObject = bt.btPairCachingGhostObject_create(); bt.btCollisionObject_setUserIndex(ghostObject, this.id); bt.btCollisionObject_setCollisionFlags(ghostObject, PhysicsComponent.COLLISIONFLAGS_CHARACTER_OBJECT); this._btColliderObject = ghostObject; (this._colliderShape) && (this._constructCharacter()); super._onAdded(); } _addToSimulation() { this._simulation._characters.push(this); this._simulation._addCharacter(this, this._collisionGroup, this._canCollideWith); } _removeFromSimulation() { this._simulation._removeCharacter(this); var characters = this._simulation._characters; characters.splice(characters.indexOf(this), 1); } _cloneTo(dest) { super._cloneTo(dest); var destCharacterController = dest; destCharacterController.stepHeight = this._stepHeight; destCharacterController.upAxis = this._upAxis; destCharacterController.maxSlope = this._maxSlope; destCharacterController.jumpSpeed = this._jumpSpeed; destCharacterController.fallSpeed = this._fallSpeed; destCharacterController.gravity = this._gravity; } _onDestroy() { ILaya3D.Physics3D._bullet.btKinematicCharacterController_destroy(this._btKinematicCharacter); super._onDestroy(); this._btKinematicCharacter = null; } move(movement) { var btMovement = CharacterController._btVector30; var bt = ILaya3D.Physics3D._bullet; bt.btVector3_setValue(btMovement, -movement.x, movement.y, movement.z); bt.btKinematicCharacterController_setWalkDirection(this._btKinematicCharacter, btMovement); } jump(velocity = null) { var bt = ILaya3D.Physics3D._bullet; var btVelocity = CharacterController._btVector30; if (velocity) { Utils3D._convertToBulletVec3(velocity, btVelocity, true); bt.btKinematicCharacterController_jump(this._btKinematicCharacter, btVelocity); } else { bt.btVector3_setValue(btVelocity, 0, 0, 0); bt.btKinematicCharacterController_jump(this._btKinematicCharacter, btVelocity); } } } CharacterController.UPAXIS_X = 0; CharacterController.UPAXIS_Y = 1; CharacterController.UPAXIS_Z = 2; class PhysicsTriggerComponent extends PhysicsComponent { constructor(collisionGroup, canCollideWith) { super(collisionGroup, canCollideWith); this._isTrigger = false; } get isTrigger() { return this._isTrigger; } set isTrigger(value) { this._isTrigger = value; var bt = ILaya3D.Physics3D._bullet; if (this._btColliderObject) { var flags = bt.btCollisionObject_getCollisionFlags(this._btColliderObject); if (value) { if ((flags & PhysicsComponent.COLLISIONFLAGS_NO_CONTACT_RESPONSE) === 0) bt.btCollisionObject_setCollisionFlags(this._btColliderObject, flags | PhysicsComponent.COLLISIONFLAGS_NO_CONTACT_RESPONSE); } else { if ((flags & PhysicsComponent.COLLISIONFLAGS_NO_CONTACT_RESPONSE) !== 0) bt.btCollisionObject_setCollisionFlags(this._btColliderObject, flags ^ PhysicsComponent.COLLISIONFLAGS_NO_CONTACT_RESPONSE); } } } _onAdded() { super._onAdded(); this.isTrigger = this._isTrigger; } _cloneTo(dest) { super._cloneTo(dest); dest.isTrigger = this._isTrigger; } } class Rigidbody3D extends PhysicsTriggerComponent { constructor(collisionGroup = Physics3DUtils.COLLISIONFILTERGROUP_DEFAULTFILTER, canCollideWith = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER) { super(collisionGroup, canCollideWith); this._isKinematic = false; this._mass = 1.0; this._gravity = new Vector3(0, -10, 0); this._angularDamping = 0.0; this._linearDamping = 0.0; this._overrideGravity = false; this._totalTorque = new Vector3(0, 0, 0); this._totalForce = new Vector3(0, 0, 0); this._linearVelocity = new Vector3(); this._angularVelocity = new Vector3(); this._linearFactor = new Vector3(1, 1, 1); this._angularFactor = new Vector3(1, 1, 1); this._detectCollisions = true; this._controlBySimulation = true; } static __init__() { var bt = ILaya3D.Physics3D._bullet; Rigidbody3D._btTempVector30 = bt.btVector3_create(0, 0, 0); Rigidbody3D._btTempVector31 = bt.btVector3_create(0, 0, 0); Rigidbody3D._btVector3Zero = bt.btVector3_create(0, 0, 0); Rigidbody3D._btInertia = bt.btVector3_create(0, 0, 0); Rigidbody3D._btImpulse = bt.btVector3_create(0, 0, 0); Rigidbody3D._btImpulseOffset = bt.btVector3_create(0, 0, 0); Rigidbody3D._btGravity = bt.btVector3_create(0, 0, 0); Rigidbody3D._btTransform0 = bt.btTransform_create(); } get mass() { return this._mass; } set mass(value) { value = Math.max(value, 1e-07); this._mass = value; (this._isKinematic) || (this._updateMass(value)); } get isKinematic() { return this._isKinematic; } set isKinematic(value) { this._isKinematic = value; this._controlBySimulation = !value; var bt = ILaya3D.Physics3D._bullet; var canInSimulation = !!(this._simulation && this._enabled && this._colliderShape); canInSimulation && this._removeFromSimulation(); var natColObj = this._btColliderObject; var flags = bt.btCollisionObject_getCollisionFlags(natColObj); if (value) { flags = flags | PhysicsComponent.COLLISIONFLAGS_KINEMATIC_OBJECT; bt.btCollisionObject_setCollisionFlags(natColObj, flags); bt.btCollisionObject_forceActivationState(this._btColliderObject, PhysicsComponent.ACTIVATIONSTATE_DISABLE_DEACTIVATION); this._enableProcessCollisions = false; this._updateMass(0); } else { if ((flags & PhysicsComponent.COLLISIONFLAGS_KINEMATIC_OBJECT) > 0) flags = flags ^ PhysicsComponent.COLLISIONFLAGS_KINEMATIC_OBJECT; bt.btCollisionObject_setCollisionFlags(natColObj, flags); bt.btCollisionObject_setActivationState(this._btColliderObject, PhysicsComponent.ACTIVATIONSTATE_ACTIVE_TAG); this._enableProcessCollisions = true; this._updateMass(this._mass); } var btZero = Rigidbody3D._btVector3Zero; bt.btCollisionObject_setInterpolationLinearVelocity(natColObj, btZero); bt.btRigidBody_setLinearVelocity(natColObj, btZero); bt.btCollisionObject_setInterpolationAngularVelocity(natColObj, btZero); bt.btRigidBody_setAngularVelocity(natColObj, btZero); canInSimulation && this._addToSimulation(); } get linearDamping() { return this._linearDamping; } set linearDamping(value) { this._linearDamping = value; if (this._btColliderObject) ILaya3D.Physics3D._bullet.btRigidBody_setDamping(this._btColliderObject, value, this._angularDamping); } get angularDamping() { return this._angularDamping; } set angularDamping(value) { this._angularDamping = value; if (this._btColliderObject) ILaya3D.Physics3D._bullet.btRigidBody_setDamping(this._btColliderObject, this._linearDamping, value); } get overrideGravity() { return this._overrideGravity; } set overrideGravity(value) { this._overrideGravity = value; var bt = ILaya3D.Physics3D._bullet; if (this._btColliderObject) { var flag = bt.btRigidBody_getFlags(this._btColliderObject); if (value) { if ((flag & Rigidbody3D._BT_DISABLE_WORLD_GRAVITY) === 0) bt.btRigidBody_setFlags(this._btColliderObject, flag | Rigidbody3D._BT_DISABLE_WORLD_GRAVITY); } else { if ((flag & Rigidbody3D._BT_DISABLE_WORLD_GRAVITY) > 0) bt.btRigidBody_setFlags(this._btColliderObject, flag ^ Rigidbody3D._BT_DISABLE_WORLD_GRAVITY); } } } get gravity() { return this._gravity; } set gravity(value) { this._gravity = value; var bt = ILaya3D.Physics3D._bullet; bt.btVector3_setValue(Rigidbody3D._btGravity, -value.x, value.y, value.z); bt.btRigidBody_setGravity(this._btColliderObject, Rigidbody3D._btGravity); } get totalForce() { if (this._btColliderObject) { var btTotalForce = ILaya3D.Physics3D._bullet.btRigidBody_getTotalForce(this._btColliderObject); Utils3D._convertToLayaVec3(btTotalForce, this._totalForce, true); return this._totalForce; } return null; } get linearFactor() { return this._linearFactor; } set linearFactor(value) { this._linearFactor = value; var btValue = Rigidbody3D._btTempVector30; Utils3D._convertToBulletVec3(value, btValue, false); ILaya3D.Physics3D._bullet.btRigidBody_setLinearFactor(this._btColliderObject, btValue); } get linearVelocity() { if (this._btColliderObject) Utils3D._convertToLayaVec3(ILaya3D.Physics3D._bullet.btRigidBody_getLinearVelocity(this._btColliderObject), this._linearVelocity, true); return this._linearVelocity; } set linearVelocity(value) { this._linearVelocity = value; if (this._btColliderObject) { var btValue = Rigidbody3D._btTempVector30; Utils3D._convertToBulletVec3(value, btValue, true); (this.isSleeping) && (this.wakeUp()); ILaya3D.Physics3D._bullet.btRigidBody_setLinearVelocity(this._btColliderObject, btValue); } } get angularFactor() { return this._angularFactor; } set angularFactor(value) { this._angularFactor = value; var btValue = Rigidbody3D._btTempVector30; Utils3D._convertToBulletVec3(value, btValue, false); ILaya3D.Physics3D._bullet.btRigidBody_setAngularFactor(this._btColliderObject, btValue); } get angularVelocity() { if (this._btColliderObject) Utils3D._convertToLayaVec3(ILaya3D.Physics3D._bullet.btRigidBody_getAngularVelocity(this._btColliderObject), this._angularVelocity, true); return this._angularVelocity; } set angularVelocity(value) { this._angularVelocity = value; if (this._btColliderObject) { var btValue = Rigidbody3D._btTempVector30; Utils3D._convertToBulletVec3(value, btValue, true); (this.isSleeping) && (this.wakeUp()); ILaya3D.Physics3D._bullet.btRigidBody_setAngularVelocity(this._btColliderObject, btValue); } } get totalTorque() { if (this._btColliderObject) { var btTotalTorque = ILaya3D.Physics3D._bullet.btRigidBody_getTotalTorque(this._btColliderObject); Utils3D._convertToLayaVec3(btTotalTorque, this._totalTorque, true); return this._totalTorque; } return null; } get detectCollisions() { return this._detectCollisions; } set detectCollisions(value) { if (this._detectCollisions !== value) { this._detectCollisions = value; if (this._colliderShape && this._enabled && this._simulation) { this._simulation._removeRigidBody(this); this._simulation._addRigidBody(this, this._collisionGroup, value ? this._canCollideWith : 0); } } } get isSleeping() { if (this._btColliderObject) return ILaya3D.Physics3D._bullet.btCollisionObject_getActivationState(this._btColliderObject) === PhysicsComponent.ACTIVATIONSTATE_ISLAND_SLEEPING; return false; } get sleepLinearVelocity() { return ILaya3D.Physics3D._bullet.btRigidBody_getLinearSleepingThreshold(this._btColliderObject); } set sleepLinearVelocity(value) { var bt = ILaya3D.Physics3D._bullet; bt.btRigidBody_setSleepingThresholds(this._btColliderObject, value, bt.btRigidBody_getAngularSleepingThreshold(this._btColliderObject)); } get sleepAngularVelocity() { return ILaya3D.Physics3D._bullet.btRigidBody_getAngularSleepingThreshold(this._btColliderObject); } set sleepAngularVelocity(value) { var bt = ILaya3D.Physics3D._bullet; bt.btRigidBody_setSleepingThresholds(this._btColliderObject, bt.btRigidBody_getLinearSleepingThreshold(this._btColliderObject), value); } get btColliderObject() { return this._btColliderObject; } set constaintRigidbodyA(value) { this._constaintRigidbodyA = value; } get constaintRigidbodyA() { return this._constaintRigidbodyA; } set constaintRigidbodyB(value) { this._constaintRigidbodyB = value; } get constaintRigidbodyB() { return this._constaintRigidbodyB; } _updateMass(mass) { if (this._btColliderObject && this._colliderShape) { var bt = ILaya3D.Physics3D._bullet; bt.btCollisionShape_calculateLocalInertia(this._colliderShape._btShape, mass, Rigidbody3D._btInertia); bt.btRigidBody_setMassProps(this._btColliderObject, mass, Rigidbody3D._btInertia); bt.btRigidBody_updateInertiaTensor(this._btColliderObject); } } _onScaleChange(scale) { super._onScaleChange(scale); this._updateMass(this._isKinematic ? 0 : this._mass); } _derivePhysicsTransformation(force) { var bt = ILaya3D.Physics3D._bullet; var btColliderObject = this._btColliderObject; var oriTransform = bt.btCollisionObject_getWorldTransform(btColliderObject); var transform = Rigidbody3D._btTransform0; bt.btTransform_equal(transform, oriTransform); this._innerDerivePhysicsTransformation(transform, force); bt.btRigidBody_setCenterOfMassTransform(btColliderObject, transform); } _onAdded() { var bt = ILaya3D.Physics3D._bullet; var motionState = bt.layaMotionState_create(); bt.layaMotionState_set_rigidBodyID(motionState, this._id); this._btLayaMotionState = motionState; var constructInfo = bt.btRigidBodyConstructionInfo_create(0.0, motionState, null, Rigidbody3D._btVector3Zero); var btRigid = bt.btRigidBody_create(constructInfo); bt.btCollisionObject_setUserIndex(btRigid, this.id); this._btColliderObject = btRigid; super._onAdded(); this.mass = this._mass; this.linearFactor = this._linearFactor; this.angularFactor = this._angularFactor; this.linearDamping = this._linearDamping; this.angularDamping = this._angularDamping; this.overrideGravity = this._overrideGravity; this.gravity = this._gravity; this.isKinematic = this._isKinematic; bt.btRigidBodyConstructionInfo_destroy(constructInfo); } _onEnable() { super._onEnable(); if (this._constaintRigidbodyA) { if (this._constaintRigidbodyA.connectedBody._simulation) { this._constaintRigidbodyA._createConstraint(); this._constaintRigidbodyA._onEnable(); } } if (this._constaintRigidbodyB) { if (this._constaintRigidbodyB.ownBody._simulation) { this._constaintRigidbodyB._createConstraint(); this._constaintRigidbodyB._onEnable(); } } } _onShapeChange(colShape) { super._onShapeChange(colShape); if (this._isKinematic) { this._updateMass(0); } else { var bt = ILaya3D.Physics3D._bullet; bt.btRigidBody_setCenterOfMassTransform(this._btColliderObject, bt.btCollisionObject_getWorldTransform(this._btColliderObject)); this._updateMass(this._mass); } } _parse(data) { (data.friction != null) && (this.friction = data.friction); (data.rollingFriction != null) && (this.rollingFriction = data.rollingFriction); (data.restitution != null) && (this.restitution = data.restitution); (data.isTrigger != null) && (this.isTrigger = data.isTrigger); (data.mass != null) && (this.mass = data.mass); (data.linearDamping != null) && (this.linearDamping = data.linearDamping); (data.angularDamping != null) && (this.angularDamping = data.angularDamping); (data.overrideGravity != null) && (this.overrideGravity = data.overrideGravity); if (data.linearFactor != null) { var linFac = this.linearFactor; linFac.fromArray(data.linearFactor); this.linearFactor = linFac; } if (data.angularFactor != null) { var angFac = this.angularFactor; angFac.fromArray(data.angularFactor); this.angularFactor = angFac; } if (data.gravity) { this.gravity.fromArray(data.gravity); this.gravity = this.gravity; } super._parse(data); this._parseShape(data.shapes); (data.isKinematic != null) && (this._isKinematic = data.isKinematic); } _onDestroy() { ILaya3D.Physics3D._bullet.btMotionState_destroy(this._btLayaMotionState); super._onDestroy(); this._btLayaMotionState = null; this._gravity = null; this._totalTorque = null; this._linearVelocity = null; this._angularVelocity = null; this._linearFactor = null; this._angularFactor = null; if (this.constaintRigidbodyA) this.constaintRigidbodyA._breakConstrained(); if (this.constaintRigidbodyB) { this.constaintRigidbodyB.connectedBody = null; this.constaintRigidbodyB._onDisable(); } } _addToSimulation() { this._simulation._addRigidBody(this, this._collisionGroup, this._detectCollisions ? this._canCollideWith : 0); } _removeFromSimulation() { this._simulation._removeRigidBody(this); } _cloneTo(dest) { super._cloneTo(dest); var destRigidbody3D = dest; destRigidbody3D.isKinematic = this._isKinematic; destRigidbody3D.mass = this._mass; destRigidbody3D.gravity = this._gravity; destRigidbody3D.angularDamping = this._angularDamping; destRigidbody3D.linearDamping = this._linearDamping; destRigidbody3D.overrideGravity = this._overrideGravity; destRigidbody3D.linearVelocity = this._linearVelocity; destRigidbody3D.angularVelocity = this._angularVelocity; destRigidbody3D.linearFactor = this._linearFactor; destRigidbody3D.angularFactor = this._angularFactor; destRigidbody3D.detectCollisions = this._detectCollisions; } applyForce(force, localOffset = null) { if (this._btColliderObject == null) throw "Attempted to call a Physics function that is avaliable only when the Entity has been already added to the Scene."; var bt = ILaya3D.Physics3D._bullet; var btForce = Rigidbody3D._btTempVector30; bt.btVector3_setValue(btForce, -force.x, force.y, force.z); if (localOffset) { var btOffset = Rigidbody3D._btTempVector31; bt.btVector3_setValue(btOffset, -localOffset.x, localOffset.y, localOffset.z); bt.btRigidBody_applyForce(this._btColliderObject, btForce, btOffset); } else { bt.btRigidBody_applyCentralForce(this._btColliderObject, btForce); } } applyTorque(torque) { if (this._btColliderObject == null) throw "Attempted to call a Physics function that is avaliable only when the Entity has been already added to the Scene."; var bullet = ILaya3D.Physics3D._bullet; var btTorque = Rigidbody3D._btTempVector30; bullet.btVector3_setValue(btTorque, -torque.x, torque.y, torque.z); bullet.btRigidBody_applyTorque(this._btColliderObject, btTorque); } applyImpulse(impulse, localOffset = null) { if (this._btColliderObject == null) throw "Attempted to call a Physics function that is avaliable only when the Entity has been already added to the Scene."; var bt = ILaya3D.Physics3D._bullet; bt.btVector3_setValue(Rigidbody3D._btImpulse, -impulse.x, impulse.y, impulse.z); if (localOffset) { bt.btVector3_setValue(Rigidbody3D._btImpulseOffset, -localOffset.x, localOffset.y, localOffset.z); bt.btRigidBody_applyImpulse(this._btColliderObject, Rigidbody3D._btImpulse, Rigidbody3D._btImpulseOffset); } else { bt.btRigidBody_applyCentralImpulse(this._btColliderObject, Rigidbody3D._btImpulse); } } applyTorqueImpulse(torqueImpulse) { if (this._btColliderObject == null) throw "Attempted to call a Physics function that is avaliable only when the Entity has been already added to the Scene."; var bt = ILaya3D.Physics3D._bullet; var btTorqueImpulse = Rigidbody3D._btTempVector30; bt.btVector3_setValue(btTorqueImpulse, -torqueImpulse.x, torqueImpulse.y, torqueImpulse.z); bt.btRigidBody_applyTorqueImpulse(this._btColliderObject, btTorqueImpulse); } wakeUp() { this._btColliderObject && (ILaya3D.Physics3D._bullet.btCollisionObject_activate(this._btColliderObject, false)); } clearForces() { var rigidBody = this._btColliderObject; if (rigidBody == null) throw "Attempted to call a Physics function that is avaliable only when the Entity has been already added to the Scene."; var bt = ILaya3D.Physics3D._bullet; bt.btRigidBody_clearForces(rigidBody); var btZero = Rigidbody3D._btVector3Zero; bt.btCollisionObject_setInterpolationLinearVelocity(rigidBody, btZero); bt.btRigidBody_setLinearVelocity(rigidBody, btZero); bt.btCollisionObject_setInterpolationAngularVelocity(rigidBody, btZero); bt.btRigidBody_setAngularVelocity(rigidBody, btZero); } } Rigidbody3D.TYPE_STATIC = 0; Rigidbody3D.TYPE_DYNAMIC = 1; Rigidbody3D.TYPE_KINEMATIC = 2; Rigidbody3D._BT_DISABLE_WORLD_GRAVITY = 1; Rigidbody3D._BT_ENABLE_GYROPSCOPIC_FORCE = 2; class Physics3D { static __bulletinit__() { this._bullet = window.Physics3D; if (this._bullet) { StaticPlaneColliderShape.__init__(); ColliderShape.__init__(); CompoundColliderShape.__init__(); PhysicsComponent.__init__(); PhysicsSimulation.__init__(); BoxColliderShape.__init__(); CylinderColliderShape.__init__(); CharacterController.__init__(); Rigidbody3D.__init__(); } } static __cannoninit__() { this._cannon = window.CANNON; if (!this._cannon) return; Laya.CannonColliderShape.__init__(); Laya.CannonPhysicsComponent.__init__(); Laya.CannonPhysicsSimulation.__init__(); Laya.CannonBoxColliderShape.__init__(); Laya.CannonRigidbody3D.__init__(); } } Physics3D._bullet = null; Physics3D._cannon = null; Physics3D._enablePhysics = false; class Config3D { constructor() { this._defaultPhysicsMemory = 16; this._maxLightCount = 32; this._lightClusterCount = new Vector3(12, 12, 12); this._editerEnvironment = false; this.isAntialias = true; this.isAlpha = false; this.premultipliedAlpha = true; this.isStencil = true; this.enableMultiLight = true; this.octreeCulling = false; this.octreeInitialSize = 64.0; this.octreeInitialCenter = new Vector3(0, 0, 0); this.octreeMinNodeSize = 2.0; this.octreeLooseness = 1.25; this.debugFrustumCulling = false; this.pbrRenderQuality = exports.PBRRenderQuality.High; this.isUseCannonPhysicsEngine = false; this._maxAreaLightCountPerClusterAverage = Math.min(Math.floor(2048 / this._lightClusterCount.z - 1) * 4, this._maxLightCount); } static get useCannonPhysics() { return Config3D._config.isUseCannonPhysicsEngine; } static set useCannonPhysics(value) { Config3D._config.isUseCannonPhysicsEngine = value; if (value) { Physics3D.__cannoninit__(); if (!ILaya3D.Scene3D.cannonPhysicsSettings) ILaya3D.Scene3D.cannonPhysicsSettings = new Laya.CannonPhysicsSettings(); } } get defaultPhysicsMemory() { return this._defaultPhysicsMemory; } set defaultPhysicsMemory(value) { if (value < 16) throw "defaultPhysicsMemory must large than 16M"; this._defaultPhysicsMemory = value; } get maxLightCount() { return this._maxLightCount; } set maxLightCount(value) { if (value > 2048) { this._maxLightCount = 2048; console.warn("Config3D: maxLightCount must less equal 2048."); } else { this._maxLightCount = value; } } get lightClusterCount() { return this._lightClusterCount; } set lightClusterCount(value) { if (value.x > 128 || value.y > 128 || value.z > 128) { this._lightClusterCount.setValue(Math.min(value.x, 128), Math.min(value.y, 128), Math.min(value.z, 128)); console.warn("Config3D: lightClusterCount X and Y、Z must less equal 128."); } else { value.cloneTo(this._lightClusterCount); } var maxAreaLightCountWithZ = Math.floor(2048 / this._lightClusterCount.z - 1) * 4; if (maxAreaLightCountWithZ < this._maxLightCount) console.warn("Config3D: if the area light(PointLight、SpotLight) count is large than " + maxAreaLightCountWithZ + ",maybe the far away culster will ingonre some light."); this._maxAreaLightCountPerClusterAverage = Math.min(maxAreaLightCountWithZ, this._maxLightCount); } cloneTo(dest) { var destConfig3D = dest; destConfig3D._defaultPhysicsMemory = this._defaultPhysicsMemory; destConfig3D._editerEnvironment = this._editerEnvironment; destConfig3D.isAntialias = this.isAntialias; destConfig3D.isAlpha = this.isAlpha; destConfig3D.premultipliedAlpha = this.premultipliedAlpha; destConfig3D.isStencil = this.isStencil; destConfig3D.octreeCulling = this.octreeCulling; this.octreeInitialCenter.cloneTo(destConfig3D.octreeInitialCenter); destConfig3D.octreeInitialSize = this.octreeInitialSize; destConfig3D.octreeMinNodeSize = this.octreeMinNodeSize; destConfig3D.octreeLooseness = this.octreeLooseness; destConfig3D.debugFrustumCulling = this.debugFrustumCulling; destConfig3D.maxLightCount = this.maxLightCount; destConfig3D.enableMultiLight = this.enableMultiLight; var lightClusterCount = destConfig3D.lightClusterCount; this.lightClusterCount.cloneTo(lightClusterCount); destConfig3D.lightClusterCount = lightClusterCount; destConfig3D.pbrRenderQuality = this.pbrRenderQuality; } clone() { var dest = new Config3D(); this.cloneTo(dest); return dest; } } Config3D._config = new Config3D(); window.Config3D = Config3D; class KeyframeNode { constructor() { this._ownerPath = []; this._propertys = []; this._keyFrames = []; } get ownerPathCount() { return this._ownerPath.length; } get propertyCount() { return this._propertys.length; } get keyFramesCount() { return this._keyFrames.length; } _setOwnerPathCount(value) { this._ownerPath.length = value; } _setOwnerPathByIndex(index, value) { this._ownerPath[index] = value; } _joinOwnerPath(sep) { return this._ownerPath.join(sep); } _setPropertyCount(value) { this._propertys.length = value; } _setPropertyByIndex(index, value) { this._propertys[index] = value; } _joinProperty(sep) { return this._propertys.join(sep); } _setKeyframeCount(value) { this._keyFrames.length = value; } _setKeyframeByIndex(index, value) { this._keyFrames[index] = value; } getOwnerPathByIndex(index) { return this._ownerPath[index]; } getPropertyByIndex(index) { return this._propertys[index]; } getKeyframeByIndex(index) { return this._keyFrames[index]; } } class AnimationEvent { constructor() { } } class Keyframe { constructor() { } cloneTo(destObject) { var destKeyFrame = destObject; destKeyFrame.time = this.time; } clone() { var dest = new Keyframe(); this.cloneTo(dest); return dest; } } class FloatKeyframe extends Keyframe { constructor() { super(); } cloneTo(destObject) { super.cloneTo(destObject); var destKeyFrame = destObject; destKeyFrame.inTangent = this.inTangent; destKeyFrame.outTangent = this.outTangent; destKeyFrame.value = this.value; } } class QuaternionKeyframe extends Keyframe { constructor() { super(); this.inTangent = new Vector4(); this.outTangent = new Vector4(); this.value = new Quaternion(); } cloneTo(dest) { super.cloneTo(dest); var destKeyFarme = dest; this.inTangent.cloneTo(destKeyFarme.inTangent); this.outTangent.cloneTo(destKeyFarme.outTangent); this.value.cloneTo(destKeyFarme.value); } } class Vector3Keyframe extends Keyframe { constructor() { super(); this.inTangent = new Vector3(); this.outTangent = new Vector3(); this.value = new Vector3(); } cloneTo(dest) { super.cloneTo(dest); var destKeyFarme = dest; this.inTangent.cloneTo(destKeyFarme.inTangent); this.outTangent.cloneTo(destKeyFarme.outTangent); this.value.cloneTo(destKeyFarme.value); } } class AnimationClipParser03 { static READ_DATA() { AnimationClipParser03._DATA.offset = AnimationClipParser03._reader.getUint32(); AnimationClipParser03._DATA.size = AnimationClipParser03._reader.getUint32(); } static READ_BLOCK() { var count = AnimationClipParser03._BLOCK.count = AnimationClipParser03._reader.getUint16(); var blockStarts = AnimationClipParser03._BLOCK.blockStarts = []; var blockLengths = AnimationClipParser03._BLOCK.blockLengths = []; for (var i = 0; i < count; i++) { blockStarts.push(AnimationClipParser03._reader.getUint32()); blockLengths.push(AnimationClipParser03._reader.getUint32()); } } static READ_STRINGS() { var offset = AnimationClipParser03._reader.getUint32(); var count = AnimationClipParser03._reader.getUint16(); var prePos = AnimationClipParser03._reader.pos; AnimationClipParser03._reader.pos = offset + AnimationClipParser03._DATA.offset; for (var i = 0; i < count; i++) AnimationClipParser03._strings[i] = AnimationClipParser03._reader.readUTFString(); AnimationClipParser03._reader.pos = prePos; } static parse(clip, reader) { AnimationClipParser03._animationClip = clip; AnimationClipParser03._reader = reader; var arrayBuffer = reader.__getBuffer(); AnimationClipParser03.READ_DATA(); AnimationClipParser03.READ_BLOCK(); AnimationClipParser03.READ_STRINGS(); for (var i = 0, n = AnimationClipParser03._BLOCK.count; i < n; i++) { var index = reader.getUint16(); var blockName = AnimationClipParser03._strings[index]; var fn = AnimationClipParser03["READ_" + blockName]; if (fn == null) throw new Error("model file err,no this function:" + index + " " + blockName); else fn.call(null); } } static READ_ANIMATIONS() { var i, j; var node; var reader = AnimationClipParser03._reader; var buffer = reader.__getBuffer(); var startTimeTypes = []; var startTimeTypeCount = reader.getUint16(); startTimeTypes.length = startTimeTypeCount; for (i = 0; i < startTimeTypeCount; i++) startTimeTypes[i] = reader.getFloat32(); var clip = AnimationClipParser03._animationClip; clip.name = AnimationClipParser03._strings[reader.getUint16()]; var clipDur = clip._duration = reader.getFloat32(); clip.islooping = !!reader.getByte(); clip._frameRate = reader.getInt16(); var nodeCount = reader.getInt16(); var nodes = clip._nodes; nodes.count = nodeCount; var nodesMap = clip._nodesMap = {}; var nodesDic = clip._nodesDic = {}; for (i = 0; i < nodeCount; i++) { node = new KeyframeNode(); nodes.setNodeByIndex(i, node); node._indexInList = i; var type = node.type = reader.getUint8(); var pathLength = reader.getUint16(); node._setOwnerPathCount(pathLength); for (j = 0; j < pathLength; j++) node._setOwnerPathByIndex(j, AnimationClipParser03._strings[reader.getUint16()]); var nodePath = node._joinOwnerPath("/"); var mapArray = nodesMap[nodePath]; (mapArray) || (nodesMap[nodePath] = mapArray = []); mapArray.push(node); node.propertyOwner = AnimationClipParser03._strings[reader.getUint16()]; var propertyLength = reader.getUint16(); node._setPropertyCount(propertyLength); for (j = 0; j < propertyLength; j++) node._setPropertyByIndex(j, AnimationClipParser03._strings[reader.getUint16()]); var fullPath = nodePath + "." + node.propertyOwner + "." + node._joinProperty("."); nodesDic[fullPath] = node; node.fullPath = fullPath; var keyframeCount = reader.getUint16(); node._setKeyframeCount(keyframeCount); var startTime; for (j = 0; j < keyframeCount; j++) { switch (type) { case 0: var floatKeyframe = new FloatKeyframe(); node._setKeyframeByIndex(j, floatKeyframe); startTime = floatKeyframe.time = startTimeTypes[reader.getUint16()]; floatKeyframe.inTangent = reader.getFloat32(); floatKeyframe.outTangent = reader.getFloat32(); floatKeyframe.value = reader.getFloat32(); break; case 1: case 3: case 4: var floatArrayKeyframe = new Vector3Keyframe(); node._setKeyframeByIndex(j, floatArrayKeyframe); startTime = floatArrayKeyframe.time = startTimeTypes[reader.getUint16()]; if (Laya.Render.supportWebGLPlusAnimation) { var data = floatArrayKeyframe.data = new Float32Array(3 * 3); for (var k = 0; k < 3; k++) data[k] = reader.getFloat32(); for (k = 0; k < 3; k++) data[3 + k] = reader.getFloat32(); for (k = 0; k < 3; k++) data[6 + k] = reader.getFloat32(); } else { var inTangent = floatArrayKeyframe.inTangent; var outTangent = floatArrayKeyframe.outTangent; var value = floatArrayKeyframe.value; inTangent.x = reader.getFloat32(); inTangent.y = reader.getFloat32(); inTangent.z = reader.getFloat32(); outTangent.x = reader.getFloat32(); outTangent.y = reader.getFloat32(); outTangent.z = reader.getFloat32(); value.x = reader.getFloat32(); value.y = reader.getFloat32(); value.z = reader.getFloat32(); } break; case 2: var quaArrayKeyframe = new QuaternionKeyframe(); node._setKeyframeByIndex(j, quaArrayKeyframe); startTime = quaArrayKeyframe.time = startTimeTypes[reader.getUint16()]; if (Laya.Render.supportWebGLPlusAnimation) { data = quaArrayKeyframe.data = new Float32Array(3 * 4); for (k = 0; k < 4; k++) data[k] = reader.getFloat32(); for (k = 0; k < 4; k++) data[4 + k] = reader.getFloat32(); for (k = 0; k < 4; k++) data[8 + k] = reader.getFloat32(); } else { var inTangentQua = quaArrayKeyframe.inTangent; var outTangentQua = quaArrayKeyframe.outTangent; var valueQua = quaArrayKeyframe.value; inTangentQua.x = reader.getFloat32(); inTangentQua.y = reader.getFloat32(); inTangentQua.z = reader.getFloat32(); inTangentQua.w = reader.getFloat32(); outTangentQua.x = reader.getFloat32(); outTangentQua.y = reader.getFloat32(); outTangentQua.z = reader.getFloat32(); outTangentQua.w = reader.getFloat32(); valueQua.x = reader.getFloat32(); valueQua.y = reader.getFloat32(); valueQua.z = reader.getFloat32(); valueQua.w = reader.getFloat32(); } break; default: throw "AnimationClipParser03:unknown type."; } } } var eventCount = reader.getUint16(); for (i = 0; i < eventCount; i++) { var event = new AnimationEvent(); event.time = Math.min(clipDur, reader.getFloat32()); event.eventName = AnimationClipParser03._strings[reader.getUint16()]; var params; var paramCount = reader.getUint16(); (paramCount > 0) && (event.params = params = []); for (j = 0; j < paramCount; j++) { var eventType = reader.getByte(); switch (eventType) { case 0: params.push(!!reader.getByte()); break; case 1: params.push(reader.getInt32()); break; case 2: params.push(reader.getFloat32()); break; case 3: params.push(AnimationClipParser03._strings[reader.getUint16()]); break; default: throw new Error("unknown type."); } } clip.addEvent(event); } } } AnimationClipParser03._strings = []; AnimationClipParser03._BLOCK = { count: 0 }; AnimationClipParser03._DATA = { offset: 0, size: 0 }; class HalfFloatUtils { static __init__() { for (var i = 0; i < 256; ++i) { var e = i - 127; if (e < -27) { HalfFloatUtils._baseTable[i | 0x000] = 0x0000; HalfFloatUtils._baseTable[i | 0x100] = 0x8000; HalfFloatUtils._shiftTable[i | 0x000] = 24; HalfFloatUtils._shiftTable[i | 0x100] = 24; } else if (e < -14) { HalfFloatUtils._baseTable[i | 0x000] = 0x0400 >> (-e - 14); HalfFloatUtils._baseTable[i | 0x100] = (0x0400 >> (-e - 14)) | 0x8000; HalfFloatUtils._shiftTable[i | 0x000] = -e - 1; HalfFloatUtils._shiftTable[i | 0x100] = -e - 1; } else if (e <= 15) { HalfFloatUtils._baseTable[i | 0x000] = (e + 15) << 10; HalfFloatUtils._baseTable[i | 0x100] = ((e + 15) << 10) | 0x8000; HalfFloatUtils._shiftTable[i | 0x000] = 13; HalfFloatUtils._shiftTable[i | 0x100] = 13; } else if (e < 128) { HalfFloatUtils._baseTable[i | 0x000] = 0x7c00; HalfFloatUtils._baseTable[i | 0x100] = 0xfc00; HalfFloatUtils._shiftTable[i | 0x000] = 24; HalfFloatUtils._shiftTable[i | 0x100] = 24; } else { HalfFloatUtils._baseTable[i | 0x000] = 0x7c00; HalfFloatUtils._baseTable[i | 0x100] = 0xfc00; HalfFloatUtils._shiftTable[i | 0x000] = 13; HalfFloatUtils._shiftTable[i | 0x100] = 13; } } HalfFloatUtils._mantissaTable[0] = 0; for (i = 1; i < 1024; ++i) { var m = i << 13; e = 0; while ((m & 0x00800000) === 0) { e -= 0x00800000; m <<= 1; } m &= ~0x00800000; e += 0x38800000; HalfFloatUtils._mantissaTable[i] = m | e; } for (i = 1024; i < 2048; ++i) { HalfFloatUtils._mantissaTable[i] = 0x38000000 + ((i - 1024) << 13); } HalfFloatUtils._exponentTable[0] = 0; for (i = 1; i < 31; ++i) { HalfFloatUtils._exponentTable[i] = i << 23; } HalfFloatUtils._exponentTable[31] = 0x47800000; HalfFloatUtils._exponentTable[32] = 0x80000000; for (i = 33; i < 63; ++i) { HalfFloatUtils._exponentTable[i] = 0x80000000 + ((i - 32) << 23); } HalfFloatUtils._exponentTable[63] = 0xc7800000; HalfFloatUtils._offsetTable[0] = 0; for (i = 1; i < 64; ++i) { if (i === 32) { HalfFloatUtils._offsetTable[i] = 0; } else { HalfFloatUtils._offsetTable[i] = 1024; } } } static roundToFloat16Bits(num) { HalfFloatUtils._floatView[0] = num; var f = HalfFloatUtils._uint32View[0]; var e = (f >> 23) & 0x1ff; return HalfFloatUtils._baseTable[e] + ((f & 0x007fffff) >> HalfFloatUtils._shiftTable[e]); } static convertToNumber(float16bits) { var m = float16bits >> 10; HalfFloatUtils._uint32View[0] = HalfFloatUtils._mantissaTable[HalfFloatUtils._offsetTable[m] + (float16bits & 0x3ff)] + HalfFloatUtils._exponentTable[m]; return HalfFloatUtils._floatView[0]; } } HalfFloatUtils._buffer = new ArrayBuffer(4); HalfFloatUtils._floatView = new Float32Array(HalfFloatUtils._buffer); HalfFloatUtils._uint32View = new Uint32Array(HalfFloatUtils._buffer); HalfFloatUtils._baseTable = new Uint32Array(512); HalfFloatUtils._shiftTable = new Uint32Array(512); HalfFloatUtils._mantissaTable = new Uint32Array(2048); HalfFloatUtils._exponentTable = new Uint32Array(64); HalfFloatUtils._offsetTable = new Uint32Array(64); class AnimationClipParser04 { static READ_DATA() { AnimationClipParser04._DATA.offset = AnimationClipParser04._reader.getUint32(); AnimationClipParser04._DATA.size = AnimationClipParser04._reader.getUint32(); } static READ_BLOCK() { var count = AnimationClipParser04._BLOCK.count = AnimationClipParser04._reader.getUint16(); var blockStarts = AnimationClipParser04._BLOCK.blockStarts = []; var blockLengths = AnimationClipParser04._BLOCK.blockLengths = []; for (var i = 0; i < count; i++) { blockStarts.push(AnimationClipParser04._reader.getUint32()); blockLengths.push(AnimationClipParser04._reader.getUint32()); } } static READ_STRINGS() { var offset = AnimationClipParser04._reader.getUint32(); var count = AnimationClipParser04._reader.getUint16(); var prePos = AnimationClipParser04._reader.pos; AnimationClipParser04._reader.pos = offset + AnimationClipParser04._DATA.offset; for (var i = 0; i < count; i++) AnimationClipParser04._strings[i] = AnimationClipParser04._reader.readUTFString(); AnimationClipParser04._reader.pos = prePos; } static parse(clip, reader, version) { AnimationClipParser04._animationClip = clip; AnimationClipParser04._reader = reader; AnimationClipParser04._version = version; AnimationClipParser04.READ_DATA(); AnimationClipParser04.READ_BLOCK(); AnimationClipParser04.READ_STRINGS(); for (var i = 0, n = AnimationClipParser04._BLOCK.count; i < n; i++) { var index = reader.getUint16(); var blockName = AnimationClipParser04._strings[index]; var fn = AnimationClipParser04["READ_" + blockName]; if (fn == null) throw new Error("model file err,no this function:" + index + " " + blockName); else fn.call(null); } AnimationClipParser04._version = null; AnimationClipParser04._reader = null; AnimationClipParser04._animationClip = null; } static READ_ANIMATIONS() { var i, j; var node; var reader = AnimationClipParser04._reader; var buffer = reader.__getBuffer(); var startTimeTypes = []; var startTimeTypeCount = reader.getUint16(); startTimeTypes.length = startTimeTypeCount; for (i = 0; i < startTimeTypeCount; i++) startTimeTypes[i] = reader.getFloat32(); var clip = AnimationClipParser04._animationClip; clip.name = AnimationClipParser04._strings[reader.getUint16()]; var clipDur = clip._duration = reader.getFloat32(); clip.islooping = !!reader.getByte(); clip._frameRate = reader.getInt16(); var nodeCount = reader.getInt16(); var nodes = clip._nodes; nodes.count = nodeCount; var nodesMap = clip._nodesMap = {}; var nodesDic = clip._nodesDic = {}; for (i = 0; i < nodeCount; i++) { node = new KeyframeNode(); nodes.setNodeByIndex(i, node); node._indexInList = i; var type = node.type = reader.getUint8(); var pathLength = reader.getUint16(); node._setOwnerPathCount(pathLength); for (j = 0; j < pathLength; j++) node._setOwnerPathByIndex(j, AnimationClipParser04._strings[reader.getUint16()]); var nodePath = node._joinOwnerPath("/"); var mapArray = nodesMap[nodePath]; (mapArray) || (nodesMap[nodePath] = mapArray = []); mapArray.push(node); node.propertyOwner = AnimationClipParser04._strings[reader.getUint16()]; var propertyLength = reader.getUint16(); node._setPropertyCount(propertyLength); for (j = 0; j < propertyLength; j++) node._setPropertyByIndex(j, AnimationClipParser04._strings[reader.getUint16()]); var fullPath = nodePath + "." + node.propertyOwner + "." + node._joinProperty("."); nodesDic[fullPath] = node; node.fullPath = fullPath; var keyframeCount = reader.getUint16(); node._setKeyframeCount(keyframeCount); var startTime; switch (AnimationClipParser04._version) { case "LAYAANIMATION:04": for (j = 0; j < keyframeCount; j++) { switch (type) { case 0: var floatKeyframe = new FloatKeyframe(); node._setKeyframeByIndex(j, floatKeyframe); startTime = floatKeyframe.time = startTimeTypes[reader.getUint16()]; floatKeyframe.inTangent = reader.getFloat32(); floatKeyframe.outTangent = reader.getFloat32(); floatKeyframe.value = reader.getFloat32(); break; case 1: case 3: case 4: var floatArrayKeyframe = new Vector3Keyframe(); node._setKeyframeByIndex(j, floatArrayKeyframe); startTime = floatArrayKeyframe.time = startTimeTypes[reader.getUint16()]; if (Laya.Render.supportWebGLPlusAnimation) { var data = floatArrayKeyframe.data = new Float32Array(3 * 3); for (var k = 0; k < 3; k++) data[k] = reader.getFloat32(); for (k = 0; k < 3; k++) data[3 + k] = reader.getFloat32(); for (k = 0; k < 3; k++) data[6 + k] = reader.getFloat32(); } else { var inTangent = floatArrayKeyframe.inTangent; var outTangent = floatArrayKeyframe.outTangent; var value = floatArrayKeyframe.value; inTangent.x = reader.getFloat32(); inTangent.y = reader.getFloat32(); inTangent.z = reader.getFloat32(); outTangent.x = reader.getFloat32(); outTangent.y = reader.getFloat32(); outTangent.z = reader.getFloat32(); value.x = reader.getFloat32(); value.y = reader.getFloat32(); value.z = reader.getFloat32(); } break; case 2: var quaternionKeyframe = new QuaternionKeyframe(); node._setKeyframeByIndex(j, quaternionKeyframe); startTime = quaternionKeyframe.time = startTimeTypes[reader.getUint16()]; if (Laya.Render.supportWebGLPlusAnimation) { data = quaternionKeyframe.data = new Float32Array(3 * 4); for (k = 0; k < 4; k++) data[k] = reader.getFloat32(); for (k = 0; k < 4; k++) data[4 + k] = reader.getFloat32(); for (k = 0; k < 4; k++) data[8 + k] = reader.getFloat32(); } else { var inTangentQua = quaternionKeyframe.inTangent; var outTangentQua = quaternionKeyframe.outTangent; var valueQua = quaternionKeyframe.value; inTangentQua.x = reader.getFloat32(); inTangentQua.y = reader.getFloat32(); inTangentQua.z = reader.getFloat32(); inTangentQua.w = reader.getFloat32(); outTangentQua.x = reader.getFloat32(); outTangentQua.y = reader.getFloat32(); outTangentQua.z = reader.getFloat32(); outTangentQua.w = reader.getFloat32(); valueQua.x = reader.getFloat32(); valueQua.y = reader.getFloat32(); valueQua.z = reader.getFloat32(); valueQua.w = reader.getFloat32(); } break; default: throw "AnimationClipParser04:unknown type."; } } break; case "LAYAANIMATION:COMPRESSION_04": for (j = 0; j < keyframeCount; j++) { switch (type) { case 0: floatKeyframe = new FloatKeyframe(); node._setKeyframeByIndex(j, floatKeyframe); startTime = floatKeyframe.time = startTimeTypes[reader.getUint16()]; floatKeyframe.inTangent = HalfFloatUtils.convertToNumber(reader.getUint16()); floatKeyframe.outTangent = HalfFloatUtils.convertToNumber(reader.getUint16()); floatKeyframe.value = HalfFloatUtils.convertToNumber(reader.getUint16()); break; case 1: case 3: case 4: floatArrayKeyframe = new Vector3Keyframe(); node._setKeyframeByIndex(j, floatArrayKeyframe); startTime = floatArrayKeyframe.time = startTimeTypes[reader.getUint16()]; if (Laya.Render.supportWebGLPlusAnimation) { data = floatArrayKeyframe.data = new Float32Array(3 * 3); for (k = 0; k < 3; k++) data[k] = HalfFloatUtils.convertToNumber(reader.getUint16()); for (k = 0; k < 3; k++) data[3 + k] = HalfFloatUtils.convertToNumber(reader.getUint16()); for (k = 0; k < 3; k++) data[6 + k] = HalfFloatUtils.convertToNumber(reader.getUint16()); } else { inTangent = floatArrayKeyframe.inTangent; outTangent = floatArrayKeyframe.outTangent; value = floatArrayKeyframe.value; inTangent.x = HalfFloatUtils.convertToNumber(reader.getUint16()); inTangent.y = HalfFloatUtils.convertToNumber(reader.getUint16()); inTangent.z = HalfFloatUtils.convertToNumber(reader.getUint16()); outTangent.x = HalfFloatUtils.convertToNumber(reader.getUint16()); outTangent.y = HalfFloatUtils.convertToNumber(reader.getUint16()); outTangent.z = HalfFloatUtils.convertToNumber(reader.getUint16()); value.x = HalfFloatUtils.convertToNumber(reader.getUint16()); value.y = HalfFloatUtils.convertToNumber(reader.getUint16()); value.z = HalfFloatUtils.convertToNumber(reader.getUint16()); } break; case 2: quaternionKeyframe = new QuaternionKeyframe(); node._setKeyframeByIndex(j, quaternionKeyframe); startTime = quaternionKeyframe.time = startTimeTypes[reader.getUint16()]; if (Laya.Render.supportWebGLPlusAnimation) { data = quaternionKeyframe.data = new Float32Array(3 * 4); for (k = 0; k < 4; k++) data[k] = HalfFloatUtils.convertToNumber(reader.getUint16()); for (k = 0; k < 4; k++) data[4 + k] = HalfFloatUtils.convertToNumber(reader.getUint16()); for (k = 0; k < 4; k++) data[8 + k] = HalfFloatUtils.convertToNumber(reader.getUint16()); } else { inTangentQua = quaternionKeyframe.inTangent; outTangentQua = quaternionKeyframe.outTangent; valueQua = quaternionKeyframe.value; inTangentQua.x = HalfFloatUtils.convertToNumber(reader.getUint16()); inTangentQua.y = HalfFloatUtils.convertToNumber(reader.getUint16()); inTangentQua.z = HalfFloatUtils.convertToNumber(reader.getUint16()); inTangentQua.w = HalfFloatUtils.convertToNumber(reader.getUint16()); outTangentQua.x = HalfFloatUtils.convertToNumber(reader.getUint16()); outTangentQua.y = HalfFloatUtils.convertToNumber(reader.getUint16()); outTangentQua.z = HalfFloatUtils.convertToNumber(reader.getUint16()); outTangentQua.w = HalfFloatUtils.convertToNumber(reader.getUint16()); valueQua.x = HalfFloatUtils.convertToNumber(reader.getUint16()); valueQua.y = HalfFloatUtils.convertToNumber(reader.getUint16()); valueQua.z = HalfFloatUtils.convertToNumber(reader.getUint16()); valueQua.w = HalfFloatUtils.convertToNumber(reader.getUint16()); } break; default: throw "AnimationClipParser04:unknown type."; } } break; } } var eventCount = reader.getUint16(); for (i = 0; i < eventCount; i++) { var event = new AnimationEvent(); event.time = Math.min(clipDur, reader.getFloat32()); event.eventName = AnimationClipParser04._strings[reader.getUint16()]; var params; var paramCount = reader.getUint16(); (paramCount > 0) && (event.params = params = []); for (j = 0; j < paramCount; j++) { var eventType = reader.getByte(); switch (eventType) { case 0: params.push(!!reader.getByte()); break; case 1: params.push(reader.getInt32()); break; case 2: params.push(reader.getFloat32()); break; case 3: params.push(AnimationClipParser04._strings[reader.getUint16()]); break; default: throw new Error("unknown type."); } } clip.addEvent(event); } } } AnimationClipParser04._strings = []; AnimationClipParser04._BLOCK = { count: 0 }; AnimationClipParser04._DATA = { offset: 0, size: 0 }; class KeyframeNodeList { constructor() { this._nodes = []; } get count() { return this._nodes.length; } set count(value) { this._nodes.length = value; } getNodeByIndex(index) { return this._nodes[index]; } setNodeByIndex(index, node) { this._nodes[index] = node; } } class AnimationClip extends Laya.Resource { constructor() { super(); this._nodes = new KeyframeNodeList(); this._animationEvents = []; } static _parse(data, propertyParams = null, constructParams = null) { var clip = new AnimationClip(); var reader = new Laya.Byte(data); var version = reader.readUTFString(); switch (version) { case "LAYAANIMATION:03": AnimationClipParser03.parse(clip, reader); break; case "LAYAANIMATION:04": case "LAYAANIMATION:COMPRESSION_04": AnimationClipParser04.parse(clip, reader, version); break; default: throw "unknown animationClip version."; } return clip; } static load(url, complete) { Laya.ILaya.loader.create(url, complete, null, AnimationClip.ANIMATIONCLIP); } duration() { return this._duration; } _hermiteInterpolate(frame, nextFrame, t, dur) { var t0 = frame.outTangent, t1 = nextFrame.inTangent; if (Number.isFinite(t0) && Number.isFinite(t1)) { var t2 = t * t; var t3 = t2 * t; var a = 2.0 * t3 - 3.0 * t2 + 1.0; var b = t3 - 2.0 * t2 + t; var c = t3 - t2; var d = -2.0 * t3 + 3.0 * t2; return a * frame.value + b * t0 * dur + c * t1 * dur + d * nextFrame.value; } else return frame.value; } _hermiteInterpolateVector3(frame, nextFrame, t, dur, out) { var p0 = frame.value; var tan0 = frame.outTangent; var p1 = nextFrame.value; var tan1 = nextFrame.inTangent; var t2 = t * t; var t3 = t2 * t; var a = 2.0 * t3 - 3.0 * t2 + 1.0; var b = t3 - 2.0 * t2 + t; var c = t3 - t2; var d = -2.0 * t3 + 3.0 * t2; var t0 = tan0.x, t1 = tan1.x; if (Number.isFinite(t0) && Number.isFinite(t1)) out.x = a * p0.x + b * t0 * dur + c * t1 * dur + d * p1.x; else out.x = p0.x; t0 = tan0.y, t1 = tan1.y; if (Number.isFinite(t0) && Number.isFinite(t1)) out.y = a * p0.y + b * t0 * dur + c * t1 * dur + d * p1.y; else out.y = p0.y; t0 = tan0.z, t1 = tan1.z; if (Number.isFinite(t0) && Number.isFinite(t1)) out.z = a * p0.z + b * t0 * dur + c * t1 * dur + d * p1.z; else out.z = p0.z; } _hermiteInterpolateQuaternion(frame, nextFrame, t, dur, out) { var p0 = frame.value; var tan0 = frame.outTangent; var p1 = nextFrame.value; var tan1 = nextFrame.inTangent; var t2 = t * t; var t3 = t2 * t; var a = 2.0 * t3 - 3.0 * t2 + 1.0; var b = t3 - 2.0 * t2 + t; var c = t3 - t2; var d = -2.0 * t3 + 3.0 * t2; var t0 = tan0.x, t1 = tan1.x; if (Number.isFinite(t0) && Number.isFinite(t1)) out.x = a * p0.x + b * t0 * dur + c * t1 * dur + d * p1.x; else out.x = p0.x; t0 = tan0.y, t1 = tan1.y; if (Number.isFinite(t0) && Number.isFinite(t1)) out.y = a * p0.y + b * t0 * dur + c * t1 * dur + d * p1.y; else out.y = p0.y; t0 = tan0.z, t1 = tan1.z; if (Number.isFinite(t0) && Number.isFinite(t1)) out.z = a * p0.z + b * t0 * dur + c * t1 * dur + d * p1.z; else out.z = p0.z; t0 = tan0.w, t1 = tan1.w; if (Number.isFinite(t0) && Number.isFinite(t1)) out.w = a * p0.w + b * t0 * dur + c * t1 * dur + d * p1.w; else out.w = p0.w; } _evaluateClipDatasRealTime(nodes, playCurTime, realTimeCurrentFrameIndexes, addtive, frontPlay, outDatas) { for (var i = 0, n = nodes.count; i < n; i++) { var node = nodes.getNodeByIndex(i); var type = node.type; var nextFrameIndex; var keyFrames = node._keyFrames; var keyFramesCount = keyFrames.length; var frameIndex = realTimeCurrentFrameIndexes[i]; if (frontPlay) { if ((frameIndex !== -1) && (playCurTime < keyFrames[frameIndex].time)) { frameIndex = -1; realTimeCurrentFrameIndexes[i] = frameIndex; } nextFrameIndex = frameIndex + 1; while (nextFrameIndex < keyFramesCount) { if (keyFrames[nextFrameIndex].time > playCurTime) break; frameIndex++; nextFrameIndex++; realTimeCurrentFrameIndexes[i] = frameIndex; } } else { nextFrameIndex = frameIndex + 1; if ((nextFrameIndex !== keyFramesCount) && (playCurTime > keyFrames[nextFrameIndex].time)) { frameIndex = keyFramesCount - 1; realTimeCurrentFrameIndexes[i] = frameIndex; } nextFrameIndex = frameIndex + 1; while (frameIndex > -1) { if (keyFrames[frameIndex].time < playCurTime) break; frameIndex--; nextFrameIndex--; realTimeCurrentFrameIndexes[i] = frameIndex; } } var isEnd = nextFrameIndex === keyFramesCount; switch (type) { case 0: if (frameIndex !== -1) { var frame = keyFrames[frameIndex]; if (isEnd) { outDatas[i] = frame.value; } else { var nextFarme = keyFrames[nextFrameIndex]; var d = nextFarme.time - frame.time; var t; if (d !== 0) t = (playCurTime - frame.time) / d; else t = 0; outDatas[i] = this._hermiteInterpolate(frame, nextFarme, t, d); } } else { outDatas[i] = keyFrames[0].value; } if (addtive) outDatas[i] = outDatas[i] - keyFrames[0].value; break; case 1: case 4: var clipData = outDatas[i]; this._evaluateFrameNodeVector3DatasRealTime(keyFrames, frameIndex, isEnd, playCurTime, clipData); if (addtive) { var firstFrameValue = keyFrames[0].value; clipData.x -= firstFrameValue.x; clipData.y -= firstFrameValue.y; clipData.z -= firstFrameValue.z; } break; case 2: var clipQuat = outDatas[i]; this._evaluateFrameNodeQuaternionDatasRealTime(keyFrames, frameIndex, isEnd, playCurTime, clipQuat); if (addtive) { var tempQuat = AnimationClip._tempQuaternion0; var firstFrameValueQua = keyFrames[0].value; Utils3D.quaternionConjugate(firstFrameValueQua, tempQuat); Quaternion.multiply(tempQuat, clipQuat, clipQuat); } break; case 3: clipData = outDatas[i]; this._evaluateFrameNodeVector3DatasRealTime(keyFrames, frameIndex, isEnd, playCurTime, clipData); if (addtive) { firstFrameValue = keyFrames[0].value; clipData.x /= firstFrameValue.x; clipData.y /= firstFrameValue.y; clipData.z /= firstFrameValue.z; } break; default: throw "AnimationClip:unknown node type."; } } } _evaluateClipDatasRealTimeForNative(nodes, playCurTime, realTimeCurrentFrameIndexes, addtive) { Laya.LayaGL.instance.evaluateClipDatasRealTime(nodes._nativeObj, playCurTime, realTimeCurrentFrameIndexes, addtive); } _evaluateFrameNodeVector3DatasRealTime(keyFrames, frameIndex, isEnd, playCurTime, outDatas) { if (frameIndex !== -1) { var frame = keyFrames[frameIndex]; if (isEnd) { var frameData = frame.value; outDatas.x = frameData.x; outDatas.y = frameData.y; outDatas.z = frameData.z; } else { var nextKeyFrame = keyFrames[frameIndex + 1]; var t; var startTime = frame.time; var d = nextKeyFrame.time - startTime; if (d !== 0) t = (playCurTime - startTime) / d; else t = 0; this._hermiteInterpolateVector3(frame, nextKeyFrame, t, d, outDatas); } } else { var firstFrameDatas = keyFrames[0].value; outDatas.x = firstFrameDatas.x; outDatas.y = firstFrameDatas.y; outDatas.z = firstFrameDatas.z; } } _evaluateFrameNodeQuaternionDatasRealTime(keyFrames, frameIndex, isEnd, playCurTime, outDatas) { if (frameIndex !== -1) { var frame = keyFrames[frameIndex]; if (isEnd) { var frameData = frame.value; outDatas.x = frameData.x; outDatas.y = frameData.y; outDatas.z = frameData.z; outDatas.w = frameData.w; } else { var nextKeyFrame = keyFrames[frameIndex + 1]; var t; var startTime = frame.time; var d = nextKeyFrame.time - startTime; if (d !== 0) t = (playCurTime - startTime) / d; else t = 0; this._hermiteInterpolateQuaternion(frame, nextKeyFrame, t, d, outDatas); } } else { var firstFrameDatas = keyFrames[0].value; outDatas.x = firstFrameDatas.x; outDatas.y = firstFrameDatas.y; outDatas.z = firstFrameDatas.z; outDatas.w = firstFrameDatas.w; } } _binarySearchEventIndex(time) { var start = 0; var end = this._animationEvents.length - 1; var mid; while (start <= end) { mid = Math.floor((start + end) / 2); var midValue = this._animationEvents[mid].time; if (midValue == time) return mid; else if (midValue > time) end = mid - 1; else start = mid + 1; } return start; } addEvent(event) { var index = this._binarySearchEventIndex(event.time); this._animationEvents.splice(index, 0, event); } _disposeResource() { this._nodes = null; this._nodesMap = null; } } AnimationClip.ANIMATIONCLIP = "ANIMATIONCLIP"; AnimationClip._tempQuaternion0 = new Quaternion(); class AnimatorPlayState { constructor() { this._currentState = null; } get normalizedTime() { return this._normalizedTime; } get duration() { return this._duration; } get animatorState() { return this._currentState; } _resetPlayState(startTime) { this._finish = false; this._startPlayTime = startTime; this._elapsedTime = startTime; this._playEventIndex = 0; this._lastIsFront = true; } _cloneTo(dest) { dest._finish = this._finish; dest._startPlayTime = this._startPlayTime; dest._elapsedTime = this._elapsedTime; dest._normalizedTime = this._normalizedTime; dest._normalizedPlayTime = this._normalizedPlayTime; dest._playEventIndex = this._playEventIndex; dest._lastIsFront = this._lastIsFront; } } class AnimatorControllerLayer { constructor(name) { this._defaultState = null; this._referenceCount = 0; this._playType = -1; this._crossDuration = -1; this._crossMark = 0; this._crossNodesOwnersCount = 0; this._crossNodesOwners = []; this._crossNodesOwnersIndicesMap = {}; this._srcCrossClipNodeIndices = []; this._destCrossClipNodeIndices = []; this._statesMap = {}; this._states = []; this._playStateInfo = new AnimatorPlayState(); this._crossPlayStateInfo = new AnimatorPlayState(); this.blendingMode = AnimatorControllerLayer.BLENDINGMODE_OVERRIDE; this.defaultWeight = 1.0; this.playOnWake = true; this.name = name; } get defaultState() { return this._defaultState; } set defaultState(value) { this._defaultState = value; this._statesMap[value.name] = value; } _removeClip(clipStateInfos, statesMap, index, state) { var clip = state._clip; var clipStateInfo = clipStateInfos[index]; clipStateInfos.splice(index, 1); delete statesMap[state.name]; if (this._animator) { var frameNodes = clip._nodes; var nodeOwners = clipStateInfo._nodeOwners; clip._removeReference(); for (var i = 0, n = frameNodes.count; i < n; i++) this._animator._removeKeyframeNodeOwner(nodeOwners, frameNodes.getNodeByIndex(i)); } } _getReferenceCount() { return this._referenceCount; } _addReference(count = 1) { for (var i = 0, n = this._states.length; i < n; i++) this._states[i]._addReference(count); this._referenceCount += count; } _removeReference(count = 1) { for (var i = 0, n = this._states.length; i < n; i++) this._states[i]._removeReference(count); this._referenceCount -= count; } _clearReference() { this._removeReference(-this._referenceCount); } getCurrentPlayState() { return this._playStateInfo; } getAnimatorState(name) { var state = this._statesMap[name]; return state ? state : null; } addState(state) { var stateName = state.name; if (this._statesMap[stateName]) { throw "AnimatorControllerLayer:this stat's name has exist."; } else { this._statesMap[stateName] = state; this._states.push(state); if (this._animator) { state._clip._addReference(); this._animator._getOwnersByClip(state); } } } removeState(state) { var states = this._states; var index = -1; for (var i = 0, n = states.length; i < n; i++) { if (states[i] === state) { index = i; break; } } if (index !== -1) this._removeClip(states, this._statesMap, index, state); } destroy() { this._clearReference(); this._statesMap = null; this._states = null; this._playStateInfo = null; this._crossPlayStateInfo = null; this._defaultState = null; } cloneTo(destObject) { var dest = destObject; dest.name = this.name; dest.blendingMode = this.blendingMode; dest.defaultWeight = this.defaultWeight; dest.playOnWake = this.playOnWake; } clone() { var dest = new AnimatorControllerLayer(this.name); this.cloneTo(dest); return dest; } } AnimatorControllerLayer.BLENDINGMODE_OVERRIDE = 0; AnimatorControllerLayer.BLENDINGMODE_ADDTIVE = 1; class ConchVector4 { constructor(x = 0, y = 0, z = 0, w = 0) { var v = this.elements = new Float32Array(4); v[0] = x; v[1] = y; v[2] = z; v[3] = w; } get x() { return this.elements[0]; } set x(value) { this.elements[0] = value; } get y() { return this.elements[1]; } set y(value) { this.elements[1] = value; } get z() { return this.elements[2]; } set z(value) { this.elements[2] = value; } get w() { return this.elements[3]; } set w(value) { this.elements[3] = value; } fromArray(array, offset = 0) { this.elements[0] = array[offset + 0]; this.elements[1] = array[offset + 1]; this.elements[2] = array[offset + 2]; this.elements[3] = array[offset + 3]; } cloneTo(destObject) { var destVector4 = destObject; var destE = destVector4.elements; var s = this.elements; destE[0] = s[0]; destE[1] = s[1]; destE[2] = s[2]; destE[3] = s[3]; } clone() { var destVector4 = new ConchVector4(); this.cloneTo(destVector4); return destVector4; } static lerp(a, b, t, out) { var e = out.elements; var f = a.elements; var g = b.elements; var ax = f[0], ay = f[1], az = f[2], aw = f[3]; e[0] = ax + t * (g[0] - ax); e[1] = ay + t * (g[1] - ay); e[2] = az + t * (g[2] - az); e[3] = aw + t * (g[3] - aw); } static transformByM4x4(vector4, m4x4, out) { var ve = vector4.elements; var vx = ve[0]; var vy = ve[1]; var vz = ve[2]; var vw = ve[3]; var me = m4x4.elements; var oe = out.elements; oe[0] = vx * me[0] + vy * me[4] + vz * me[8] + vw * me[12]; oe[1] = vx * me[1] + vy * me[5] + vz * me[9] + vw * me[13]; oe[2] = vx * me[2] + vy * me[6] + vz * me[10] + vw * me[14]; oe[3] = vx * me[3] + vy * me[7] + vz * me[11] + vw * me[15]; } static equals(a, b) { var ae = a.elements; var be = b.elements; return MathUtils3D.nearEqual(Math.abs(ae[0]), Math.abs(be[0])) && MathUtils3D.nearEqual(Math.abs(ae[1]), Math.abs(be[1])) && MathUtils3D.nearEqual(Math.abs(ae[2]), Math.abs(be[2])) && MathUtils3D.nearEqual(Math.abs(ae[3]), Math.abs(be[3])); } length() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); } lengthSquared() { return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; } static normalize(s, out) { var se = s.elements; var oe = out.elements; var len = s.length(); if (len > 0) { oe[0] = se[0] * len; oe[1] = se[1] * len; oe[2] = se[2] * len; oe[3] = se[3] * len; } } static add(a, b, out) { var oe = out.elements; var ae = a.elements; var be = b.elements; oe[0] = ae[0] + be[0]; oe[1] = ae[1] + be[1]; oe[2] = ae[2] + be[2]; oe[3] = ae[3] + be[3]; } static subtract(a, b, out) { var oe = out.elements; var ae = a.elements; var be = b.elements; oe[0] = ae[0] - be[0]; oe[1] = ae[1] - be[1]; oe[2] = ae[2] - be[2]; oe[3] = ae[3] - be[3]; } static multiply(a, b, out) { var oe = out.elements; var ae = a.elements; var be = b.elements; oe[0] = ae[0] * be[0]; oe[1] = ae[1] * be[1]; oe[2] = ae[2] * be[2]; oe[3] = ae[3] * be[3]; } static scale(a, b, out) { var oe = out.elements; var ae = a.elements; oe[0] = ae[0] * b; oe[1] = ae[1] * b; oe[2] = ae[2] * b; oe[3] = ae[3] * b; } static Clamp(value, min, max, out) { var valuee = value.elements; var x = valuee[0]; var y = valuee[1]; var z = valuee[2]; var w = valuee[3]; var mine = min.elements; var mineX = mine[0]; var mineY = mine[1]; var mineZ = mine[2]; var mineW = mine[3]; var maxe = max.elements; var maxeX = maxe[0]; var maxeY = maxe[1]; var maxeZ = maxe[2]; var maxeW = maxe[3]; var oute = out.elements; x = (x > maxeX) ? maxeX : x; x = (x < mineX) ? mineX : x; y = (y > maxeY) ? maxeY : y; y = (y < mineY) ? mineY : y; z = (z > maxeZ) ? maxeZ : z; z = (z < mineZ) ? mineZ : z; w = (w > maxeW) ? maxeW : w; w = (w < mineW) ? mineW : w; oute[0] = x; oute[1] = y; oute[2] = z; oute[3] = w; } static distanceSquared(value1, value2) { var value1e = value1.elements; var value2e = value2.elements; var x = value1e[0] - value2e[0]; var y = value1e[1] - value2e[1]; var z = value1e[2] - value2e[2]; var w = value1e[3] - value2e[3]; return (x * x) + (y * y) + (z * z) + (w * w); } static distance(value1, value2) { var value1e = value1.elements; var value2e = value2.elements; var x = value1e[0] - value2e[0]; var y = value1e[1] - value2e[1]; var z = value1e[2] - value2e[2]; var w = value1e[3] - value2e[3]; return Math.sqrt((x * x) + (y * y) + (z * z) + (w * w)); } static dot(a, b) { var ae = a.elements; var be = b.elements; var r = (ae[0] * be[0]) + (ae[1] * be[1]) + (ae[2] * be[2]) + (ae[3] * be[3]); return r; } static min(a, b, out) { var e = out.elements; var f = a.elements; var g = b.elements; e[0] = Math.min(f[0], g[0]); e[1] = Math.min(f[1], g[1]); e[2] = Math.min(f[2], g[2]); e[3] = Math.min(f[3], g[3]); } static max(a, b, out) { var e = out.elements; var f = a.elements; var g = b.elements; e[0] = Math.max(f[0], g[0]); e[1] = Math.max(f[1], g[1]); e[2] = Math.max(f[2], g[2]); e[3] = Math.max(f[3], g[3]); } } ConchVector4.ZERO = new ConchVector4(); ConchVector4.ONE = new ConchVector4(1.0, 1.0, 1.0, 1.0); ConchVector4.UnitX = new ConchVector4(1.0, 0.0, 0.0, 0.0); ConchVector4.UnitY = new ConchVector4(0.0, 1.0, 0.0, 0.0); ConchVector4.UnitZ = new ConchVector4(0.0, 0.0, 1.0, 0.0); ConchVector4.UnitW = new ConchVector4(0.0, 0.0, 0.0, 1.0); class ConchVector3 { constructor(x = 0, y = 0, z = 0, nativeElements = null) { var v; if (nativeElements) { v = nativeElements; } else { v = new Float32Array(3); } this.elements = v; v[0] = x; v[1] = y; v[2] = z; } static distanceSquared(value1, value2) { var value1e = value1.elements; var value2e = value2.elements; var x = value1e[0] - value2e[0]; var y = value1e[1] - value2e[1]; var z = value1e[2] - value2e[2]; return (x * x) + (y * y) + (z * z); } static distance(value1, value2) { var value1e = value1.elements; var value2e = value2.elements; var x = value1e[0] - value2e[0]; var y = value1e[1] - value2e[1]; var z = value1e[2] - value2e[2]; return Math.sqrt((x * x) + (y * y) + (z * z)); } static min(a, b, out) { var e = out.elements; var f = a.elements; var g = b.elements; e[0] = Math.min(f[0], g[0]); e[1] = Math.min(f[1], g[1]); e[2] = Math.min(f[2], g[2]); } static max(a, b, out) { var e = out.elements; var f = a.elements; var g = b.elements; e[0] = Math.max(f[0], g[0]); e[1] = Math.max(f[1], g[1]); e[2] = Math.max(f[2], g[2]); } static transformQuat(source, rotation, out) { var destination = out.elements; var se = source.elements; var re = rotation.elements; var x = se[0], y = se[1], z = se[2], qx = re[0], qy = re[1], qz = re[2], qw = re[3], ix = qw * x + qy * z - qz * y, iy = qw * y + qz * x - qx * z, iz = qw * z + qx * y - qy * x, iw = -qx * x - qy * y - qz * z; destination[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; destination[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; destination[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; } static scalarLength(a) { var f = a.elements; var x = f[0], y = f[1], z = f[2]; return Math.sqrt(x * x + y * y + z * z); } static scalarLengthSquared(a) { var f = a.elements; var x = f[0], y = f[1], z = f[2]; return x * x + y * y + z * z; } static normalize(s, out) { var se = s.elements; var oe = out.elements; var x = se[0], y = se[1], z = se[2]; var len = x * x + y * y + z * z; if (len > 0) { len = 1 / Math.sqrt(len); oe[0] = se[0] * len; oe[1] = se[1] * len; oe[2] = se[2] * len; } } static multiply(a, b, out) { var e = out.elements; var f = a.elements; var g = b.elements; e[0] = f[0] * g[0]; e[1] = f[1] * g[1]; e[2] = f[2] * g[2]; } static scale(a, b, out) { var e = out.elements; var f = a.elements; e[0] = f[0] * b; e[1] = f[1] * b; e[2] = f[2] * b; } static lerp(a, b, t, out) { var e = out.elements; var f = a.elements; var g = b.elements; var ax = f[0], ay = f[1], az = f[2]; e[0] = ax + t * (g[0] - ax); e[1] = ay + t * (g[1] - ay); e[2] = az + t * (g[2] - az); } static transformV3ToV3(vector, transform, result) { var intermediate = ConchVector3._tempVector4; ConchVector3.transformV3ToV4(vector, transform, intermediate); var intermediateElem = intermediate.elements; var resultElem = result.elements; resultElem[0] = intermediateElem[0]; resultElem[1] = intermediateElem[1]; resultElem[2] = intermediateElem[2]; } static transformV3ToV4(vector, transform, result) { var vectorElem = vector.elements; var vectorX = vectorElem[0]; var vectorY = vectorElem[1]; var vectorZ = vectorElem[2]; var transformElem = transform.elements; var resultElem = result.elements; resultElem[0] = (vectorX * transformElem[0]) + (vectorY * transformElem[4]) + (vectorZ * transformElem[8]) + transformElem[12]; resultElem[1] = (vectorX * transformElem[1]) + (vectorY * transformElem[5]) + (vectorZ * transformElem[9]) + transformElem[13]; resultElem[2] = (vectorX * transformElem[2]) + (vectorY * transformElem[6]) + (vectorZ * transformElem[10]) + transformElem[14]; resultElem[3] = (vectorX * transformElem[3]) + (vectorY * transformElem[7]) + (vectorZ * transformElem[11]) + transformElem[15]; } static TransformNormal(normal, transform, result) { var normalElem = normal.elements; var normalX = normalElem[0]; var normalY = normalElem[1]; var normalZ = normalElem[2]; var transformElem = transform.elements; var resultElem = result.elements; resultElem[0] = (normalX * transformElem[0]) + (normalY * transformElem[4]) + (normalZ * transformElem[8]); resultElem[1] = (normalX * transformElem[1]) + (normalY * transformElem[5]) + (normalZ * transformElem[9]); resultElem[2] = (normalX * transformElem[2]) + (normalY * transformElem[6]) + (normalZ * transformElem[10]); } static transformCoordinate(coordinate, transform, result) { var coordinateElem = coordinate.elements; var coordinateX = coordinateElem[0]; var coordinateY = coordinateElem[1]; var coordinateZ = coordinateElem[2]; var transformElem = transform.elements; var w = ((coordinateX * transformElem[3]) + (coordinateY * transformElem[7]) + (coordinateZ * transformElem[11]) + transformElem[15]); var resultElem = result.elements; resultElem[0] = (coordinateX * transformElem[0]) + (coordinateY * transformElem[4]) + (coordinateZ * transformElem[8]) + transformElem[12] / w; resultElem[1] = (coordinateX * transformElem[1]) + (coordinateY * transformElem[5]) + (coordinateZ * transformElem[9]) + transformElem[13] / w; resultElem[2] = (coordinateX * transformElem[2]) + (coordinateY * transformElem[6]) + (coordinateZ * transformElem[10]) + transformElem[14] / w; } static Clamp(value, min, max, out) { var valuee = value.elements; var x = valuee[0]; var y = valuee[1]; var z = valuee[2]; var mine = min.elements; var mineX = mine[0]; var mineY = mine[1]; var mineZ = mine[2]; var maxe = max.elements; var maxeX = maxe[0]; var maxeY = maxe[1]; var maxeZ = maxe[2]; var oute = out.elements; x = (x > maxeX) ? maxeX : x; x = (x < mineX) ? mineX : x; y = (y > maxeY) ? maxeY : y; y = (y < mineY) ? mineY : y; z = (z > maxeZ) ? maxeZ : z; z = (z < mineZ) ? mineZ : z; oute[0] = x; oute[1] = y; oute[2] = z; } static add(a, b, out) { var e = out.elements; var f = a.elements; var g = b.elements; e[0] = f[0] + g[0]; e[1] = f[1] + g[1]; e[2] = f[2] + g[2]; } static subtract(a, b, o) { var oe = o.elements; var ae = a.elements; var be = b.elements; oe[0] = ae[0] - be[0]; oe[1] = ae[1] - be[1]; oe[2] = ae[2] - be[2]; } static cross(a, b, o) { var ae = a.elements; var be = b.elements; var oe = o.elements; var ax = ae[0], ay = ae[1], az = ae[2], bx = be[0], by = be[1], bz = be[2]; oe[0] = ay * bz - az * by; oe[1] = az * bx - ax * bz; oe[2] = ax * by - ay * bx; } static dot(a, b) { var ae = a.elements; var be = b.elements; var r = (ae[0] * be[0]) + (ae[1] * be[1]) + (ae[2] * be[2]); return r; } static equals(a, b) { var ae = a.elements; var be = b.elements; return MathUtils3D.nearEqual(ae[0], be[0]) && MathUtils3D.nearEqual(ae[1], be[1]) && MathUtils3D.nearEqual(ae[2], be[2]); } get x() { return this.elements[0]; } set x(value) { this.elements[0] = value; } get y() { return this.elements[1]; } set y(value) { this.elements[1] = value; } get z() { return this.elements[2]; } set z(value) { this.elements[2] = value; } setValue(x, y, z) { this.elements[0] = x; this.elements[1] = y; this.elements[2] = z; } fromArray(array, offset = 0) { this.elements[0] = array[offset + 0]; this.elements[1] = array[offset + 1]; this.elements[2] = array[offset + 2]; } cloneTo(destObject) { var destVector3 = destObject; var destE = destVector3.elements; var s = this.elements; destE[0] = s[0]; destE[1] = s[1]; destE[2] = s[2]; } clone() { var destVector3 = new ConchVector3(); this.cloneTo(destVector3); return destVector3; } toDefault() { this.elements[0] = 0; this.elements[1] = 0; this.elements[2] = 0; } } ConchVector3._tempVector4 = new ConchVector4(); ConchVector3.ZERO = new ConchVector3(0.0, 0.0, 0.0); ConchVector3.ONE = new ConchVector3(1.0, 1.0, 1.0); ConchVector3.NegativeUnitX = new ConchVector3(-1, 0, 0); ConchVector3.UnitX = new ConchVector3(1, 0, 0); ConchVector3.UnitY = new ConchVector3(0, 1, 0); ConchVector3.UnitZ = new ConchVector3(0, 0, 1); ConchVector3.ForwardRH = new ConchVector3(0, 0, -1); ConchVector3.ForwardLH = new ConchVector3(0, 0, 1); ConchVector3.Up = new ConchVector3(0, 1, 0); ConchVector3.NAN = new ConchVector3(NaN, NaN, NaN); class ConchQuaternion { constructor(x = 0, y = 0, z = 0, w = 1, nativeElements = null) { var v; if (nativeElements) { v = nativeElements; } else { v = new Float32Array(4); } v[0] = x; v[1] = y; v[2] = z; v[3] = w; this.elements = v; } static _dotArray(l, r) { return l[0] * r[0] + l[1] * r[1] + l[2] * r[2] + l[3] * r[3]; } static _normalizeArray(f, o) { var x = f[0], y = f[1], z = f[2], w = f[3]; var len = x * x + y * y + z * z + w * w; if (len > 0) { len = 1 / Math.sqrt(len); o[0] = x * len; o[1] = y * len; o[2] = z * len; o[3] = w * len; } } static _lerpArray(l, r, amount, o) { var inverse = 1.0 - amount; if (ConchQuaternion._dotArray(l, r) >= 0) { o[0] = (inverse * l[0]) + (amount * r[0]); o[1] = (inverse * l[1]) + (amount * r[1]); o[2] = (inverse * l[2]) + (amount * r[2]); o[3] = (inverse * l[3]) + (amount * r[3]); } else { o[0] = (inverse * l[0]) - (amount * r[0]); o[1] = (inverse * l[1]) - (amount * r[1]); o[2] = (inverse * l[2]) - (amount * r[2]); o[3] = (inverse * l[3]) - (amount * r[3]); } ConchQuaternion._normalizeArray(o, o); } static createFromYawPitchRoll(yaw, pitch, roll, out) { var halfRoll = roll * 0.5; var halfPitch = pitch * 0.5; var halfYaw = yaw * 0.5; var sinRoll = Math.sin(halfRoll); var cosRoll = Math.cos(halfRoll); var sinPitch = Math.sin(halfPitch); var cosPitch = Math.cos(halfPitch); var sinYaw = Math.sin(halfYaw); var cosYaw = Math.cos(halfYaw); var oe = out.elements; oe[0] = (cosYaw * sinPitch * cosRoll) + (sinYaw * cosPitch * sinRoll); oe[1] = (sinYaw * cosPitch * cosRoll) - (cosYaw * sinPitch * sinRoll); oe[2] = (cosYaw * cosPitch * sinRoll) - (sinYaw * sinPitch * cosRoll); oe[3] = (cosYaw * cosPitch * cosRoll) + (sinYaw * sinPitch * sinRoll); } static multiply(left, right, out) { var le = left.elements; var re = right.elements; var oe = out.elements; var lx = le[0]; var ly = le[1]; var lz = le[2]; var lw = le[3]; var rx = re[0]; var ry = re[1]; var rz = re[2]; var rw = re[3]; var a = (ly * rz - lz * ry); var b = (lz * rx - lx * rz); var c = (lx * ry - ly * rx); var d = (lx * rx + ly * ry + lz * rz); oe[0] = (lx * rw + rx * lw) + a; oe[1] = (ly * rw + ry * lw) + b; oe[2] = (lz * rw + rz * lw) + c; oe[3] = lw * rw - d; } static arcTanAngle(x, y) { if (x == 0) { if (y == 1) return Math.PI / 2; return -Math.PI / 2; } if (x > 0) return Math.atan(y / x); if (x < 0) { if (y > 0) return Math.atan(y / x) + Math.PI; return Math.atan(y / x) - Math.PI; } return 0; } static angleTo(from, location, angle) { ConchVector3.subtract(location, from, ConchQuaternion.TEMPVector30); ConchVector3.normalize(ConchQuaternion.TEMPVector30, ConchQuaternion.TEMPVector30); angle.elements[0] = Math.asin(ConchQuaternion.TEMPVector30.y); angle.elements[1] = ConchQuaternion.arcTanAngle(-ConchQuaternion.TEMPVector30.z, -ConchQuaternion.TEMPVector30.x); } static createFromAxisAngle(axis, rad, out) { var e = out.elements; var f = axis.elements; rad = rad * 0.5; var s = Math.sin(rad); e[0] = s * f[0]; e[1] = s * f[1]; e[2] = s * f[2]; e[3] = Math.cos(rad); } static createFromMatrix3x3(sou, out) { var e = out.elements; var f = sou.elements; var fTrace = f[0] + f[4] + f[8]; var fRoot; if (fTrace > 0.0) { fRoot = Math.sqrt(fTrace + 1.0); e[3] = 0.5 * fRoot; fRoot = 0.5 / fRoot; e[0] = (f[5] - f[7]) * fRoot; e[1] = (f[6] - f[2]) * fRoot; e[2] = (f[1] - f[3]) * fRoot; } else { var i = 0; if (f[4] > f[0]) i = 1; if (f[8] > f[i * 3 + i]) i = 2; var j = (i + 1) % 3; var k = (i + 2) % 3; fRoot = Math.sqrt(f[i * 3 + i] - f[j * 3 + j] - f[k * 3 + k] + 1.0); e[i] = 0.5 * fRoot; fRoot = 0.5 / fRoot; e[3] = (f[j * 3 + k] - f[k * 3 + j]) * fRoot; e[j] = (f[j * 3 + i] + f[i * 3 + j]) * fRoot; e[k] = (f[k * 3 + i] + f[i * 3 + k]) * fRoot; } return; } static createFromMatrix4x4(mat, out) { var me = mat.elements; var oe = out.elements; var sqrt; var half; var scale = me[0] + me[5] + me[10]; if (scale > 0.0) { sqrt = Math.sqrt(scale + 1.0); oe[3] = sqrt * 0.5; sqrt = 0.5 / sqrt; oe[0] = (me[6] - me[9]) * sqrt; oe[1] = (me[8] - me[2]) * sqrt; oe[2] = (me[1] - me[4]) * sqrt; } else if ((me[0] >= me[5]) && (me[0] >= me[10])) { sqrt = Math.sqrt(1.0 + me[0] - me[5] - me[10]); half = 0.5 / sqrt; oe[0] = 0.5 * sqrt; oe[1] = (me[1] + me[4]) * half; oe[2] = (me[2] + me[8]) * half; oe[3] = (me[6] - me[9]) * half; } else if (me[5] > me[10]) { sqrt = Math.sqrt(1.0 + me[5] - me[0] - me[10]); half = 0.5 / sqrt; oe[0] = (me[4] + me[1]) * half; oe[1] = 0.5 * sqrt; oe[2] = (me[9] + me[6]) * half; oe[3] = (me[8] - me[2]) * half; } else { sqrt = Math.sqrt(1.0 + me[10] - me[0] - me[5]); half = 0.5 / sqrt; oe[0] = (me[8] + me[2]) * half; oe[1] = (me[9] + me[6]) * half; oe[2] = 0.5 * sqrt; oe[3] = (me[1] - me[4]) * half; } } static slerp(left, right, t, out) { var a = left.elements; var b = right.elements; var oe = out.elements; var ax = a[0], ay = a[1], az = a[2], aw = a[3], bx = b[0], by = b[1], bz = b[2], bw = b[3]; var omega, cosom, sinom, scale0, scale1; cosom = ax * bx + ay * by + az * bz + aw * bw; if (cosom < 0.0) { cosom = -cosom; bx = -bx; by = -by; bz = -bz; bw = -bw; } if ((1.0 - cosom) > 0.000001) { omega = Math.acos(cosom); sinom = Math.sin(omega); scale0 = Math.sin((1.0 - t) * omega) / sinom; scale1 = Math.sin(t * omega) / sinom; } else { scale0 = 1.0 - t; scale1 = t; } oe[0] = scale0 * ax + scale1 * bx; oe[1] = scale0 * ay + scale1 * by; oe[2] = scale0 * az + scale1 * bz; oe[3] = scale0 * aw + scale1 * bw; return oe; } static lerp(left, right, amount, out) { ConchQuaternion._lerpArray(left.elements, right.elements, amount, out.elements); } static add(left, right, out) { var e = out.elements; var f = left.elements; var g = right.elements; e[0] = f[0] + g[0]; e[1] = f[1] + g[1]; e[2] = f[2] + g[2]; e[3] = f[3] + g[3]; } static dot(left, right) { return ConchQuaternion._dotArray(left.elements, right.elements); } get x() { return this.elements[0]; } set x(value) { this.elements[0] = value; } get y() { return this.elements[1]; } set y(value) { this.elements[1] = value; } get z() { return this.elements[2]; } set z(value) { this.elements[2] = value; } get w() { return this.elements[3]; } set w(value) { this.elements[3] = value; } scaling(scaling, out) { var e = out.elements; var f = this.elements; e[0] = f[0] * scaling; e[1] = f[1] * scaling; e[2] = f[2] * scaling; e[3] = f[3] * scaling; } normalize(out) { ConchQuaternion._normalizeArray(this.elements, out.elements); } length() { var f = this.elements; var x = f[0], y = f[1], z = f[2], w = f[3]; return Math.sqrt(x * x + y * y + z * z + w * w); } rotateX(rad, out) { var e = out.elements; var f = this.elements; rad *= 0.5; var ax = f[0], ay = f[1], az = f[2], aw = f[3]; var bx = Math.sin(rad), bw = Math.cos(rad); e[0] = ax * bw + aw * bx; e[1] = ay * bw + az * bx; e[2] = az * bw - ay * bx; e[3] = aw * bw - ax * bx; } rotateY(rad, out) { var e = out.elements; var f = this.elements; rad *= 0.5; var ax = f[0], ay = f[1], az = f[2], aw = f[3], by = Math.sin(rad), bw = Math.cos(rad); e[0] = ax * bw - az * by; e[1] = ay * bw + aw * by; e[2] = az * bw + ax * by; e[3] = aw * bw - ay * by; } rotateZ(rad, out) { var e = out.elements; var f = this.elements; rad *= 0.5; var ax = f[0], ay = f[1], az = f[2], aw = f[3], bz = Math.sin(rad), bw = Math.cos(rad); e[0] = ax * bw + ay * bz; e[1] = ay * bw - ax * bz; e[2] = az * bw + aw * bz; e[3] = aw * bw - az * bz; } getYawPitchRoll(out) { ConchVector3.transformQuat(ConchVector3.ForwardRH, this, ConchQuaternion.TEMPVector31); ConchVector3.transformQuat(ConchVector3.Up, this, ConchQuaternion.TEMPVector32); var upe = ConchQuaternion.TEMPVector32.elements; ConchQuaternion.angleTo(ConchVector3.ZERO, ConchQuaternion.TEMPVector31, ConchQuaternion.TEMPVector33); var anglee = ConchQuaternion.TEMPVector33.elements; if (anglee[0] == Math.PI / 2) { anglee[1] = ConchQuaternion.arcTanAngle(upe[2], upe[0]); anglee[2] = 0; } else if (anglee[0] == -Math.PI / 2) { anglee[1] = ConchQuaternion.arcTanAngle(-upe[2], -upe[0]); anglee[2] = 0; } else { Matrix4x4.createRotationY(-anglee[1], ConchQuaternion.TEMPMatrix0); Matrix4x4.createRotationX(-anglee[0], ConchQuaternion.TEMPMatrix1); ConchVector3.transformCoordinate(ConchQuaternion.TEMPVector32, ConchQuaternion.TEMPMatrix0, ConchQuaternion.TEMPVector32); ConchVector3.transformCoordinate(ConchQuaternion.TEMPVector32, ConchQuaternion.TEMPMatrix1, ConchQuaternion.TEMPVector32); anglee[2] = ConchQuaternion.arcTanAngle(upe[1], -upe[0]); } if (anglee[1] <= -Math.PI) anglee[1] = Math.PI; if (anglee[2] <= -Math.PI) anglee[2] = Math.PI; if (anglee[1] >= Math.PI && anglee[2] >= Math.PI) { anglee[1] = 0; anglee[2] = 0; anglee[0] = Math.PI - anglee[0]; } var oe = out.elements; oe[0] = anglee[1]; oe[1] = anglee[0]; oe[2] = anglee[2]; } invert(out) { var e = out.elements; var f = this.elements; var a0 = f[0], a1 = f[1], a2 = f[2], a3 = f[3]; var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3; var invDot = dot ? 1.0 / dot : 0; e[0] = -a0 * invDot; e[1] = -a1 * invDot; e[2] = -a2 * invDot; e[3] = a3 * invDot; } identity() { var e = this.elements; e[0] = 0; e[1] = 0; e[2] = 0; e[3] = 1; } fromArray(array, offset = 0) { this.elements[0] = array[offset + 0]; this.elements[1] = array[offset + 1]; this.elements[2] = array[offset + 2]; this.elements[3] = array[offset + 3]; } cloneTo(destObject) { var i, s, d; s = this.elements; d = destObject.elements; if (s === d) { return; } for (i = 0; i < 4; ++i) { d[i] = s[i]; } } clone() { var dest = new ConchQuaternion(); this.cloneTo(dest); return dest; } equals(b) { var ae = this.elements; var be = b.elements; return MathUtils3D.nearEqual(ae[0], be[0]) && MathUtils3D.nearEqual(ae[1], be[1]) && MathUtils3D.nearEqual(ae[2], be[2]) && MathUtils3D.nearEqual(ae[3], be[3]); } static rotationLookAt(forward, up, out) { ConchQuaternion.lookAt(ConchVector3.ZERO, forward, up, out); } static lookAt(eye, target, up, out) { Matrix3x3.lookAt(eye, target, up, ConchQuaternion._tempMatrix3x3); ConchQuaternion.rotationMatrix(ConchQuaternion._tempMatrix3x3, out); } lengthSquared() { var x = this.elements[0]; var y = this.elements[1]; var z = this.elements[2]; var w = this.elements[3]; return (x * x) + (y * y) + (z * z) + (w * w); } static invert(value, out) { var vE = value.elements; var oE = out.elements; var lengthSq = value.lengthSquared(); if (!MathUtils3D.isZero(lengthSq)) { lengthSq = 1.0 / lengthSq; oE[0] = -vE[0] * lengthSq; oE[1] = -vE[1] * lengthSq; oE[2] = -vE[2] * lengthSq; oE[3] = vE[3] * lengthSq; } } static rotationMatrix(matrix3x3, out) { var me = matrix3x3.elements; var m11 = me[0]; var m12 = me[1]; var m13 = me[2]; var m21 = me[3]; var m22 = me[4]; var m23 = me[5]; var m31 = me[6]; var m32 = me[7]; var m33 = me[8]; var oe = out.elements; var sqrt, half; var scale = m11 + m22 + m33; if (scale > 0) { sqrt = Math.sqrt(scale + 1); oe[3] = sqrt * 0.5; sqrt = 0.5 / sqrt; oe[0] = (m23 - m32) * sqrt; oe[1] = (m31 - m13) * sqrt; oe[2] = (m12 - m21) * sqrt; } else if ((m11 >= m22) && (m11 >= m33)) { sqrt = Math.sqrt(1 + m11 - m22 - m33); half = 0.5 / sqrt; oe[0] = 0.5 * sqrt; oe[1] = (m12 + m21) * half; oe[2] = (m13 + m31) * half; oe[3] = (m23 - m32) * half; } else if (m22 > m33) { sqrt = Math.sqrt(1 + m22 - m11 - m33); half = 0.5 / sqrt; oe[0] = (m21 + m12) * half; oe[1] = 0.5 * sqrt; oe[2] = (m32 + m23) * half; oe[3] = (m31 - m13) * half; } else { sqrt = Math.sqrt(1 + m33 - m11 - m22); half = 0.5 / sqrt; oe[0] = (m31 + m13) * half; oe[1] = (m32 + m23) * half; oe[2] = 0.5 * sqrt; oe[3] = (m12 - m21) * half; } } } ConchQuaternion.TEMPVector30 = new ConchVector3(); ConchQuaternion.TEMPVector31 = new ConchVector3(); ConchQuaternion.TEMPVector32 = new ConchVector3(); ConchQuaternion.TEMPVector33 = new ConchVector3(); ConchQuaternion.TEMPMatrix0 = new Matrix4x4(); ConchQuaternion.TEMPMatrix1 = new Matrix4x4(); ConchQuaternion._tempMatrix3x3 = new Matrix3x3(); ConchQuaternion.DEFAULT = new ConchQuaternion(); ConchQuaternion.NAN = new ConchQuaternion(NaN, NaN, NaN, NaN); class AnimatorState { constructor() { this._referenceCount = 0; this._clip = null; this._nodeOwners = []; this._currentFrameIndices = null; this._realtimeDatas = []; this._scripts = null; this.speed = 1.0; this.clipStart = 0.0; this.clipEnd = 1.0; } get clip() { return this._clip; } set clip(value) { if (this._clip !== value) { if (this._clip) (this._referenceCount > 0) && (this._clip._removeReference(this._referenceCount)); if (value) { var realtimeDatas = this._realtimeDatas; var clipNodes = value._nodes; var count = clipNodes.count; this._currentFrameIndices = new Int16Array(count); this._resetFrameIndices(); (this._referenceCount > 0) && (value._addReference(this._referenceCount)); this._realtimeDatas.length = count; for (var i = 0; i < count; i++) { switch (clipNodes.getNodeByIndex(i).type) { case 0: break; case 1: case 3: case 4: realtimeDatas[i] = Laya.Render.supportWebGLPlusAnimation ? new ConchVector3 : new Vector3(); break; case 2: realtimeDatas[i] = Laya.Render.supportWebGLPlusAnimation ? new ConchQuaternion : new Quaternion(); break; default: throw "AnimationClipParser04:unknown type."; } } } this._clip = value; } } _getReferenceCount() { return this._referenceCount; } _addReference(count = 1) { (this._clip) && (this._clip._addReference(count)); this._referenceCount += count; } _removeReference(count = 1) { (this._clip) && (this._clip._removeReference(count)); this._referenceCount -= count; } _clearReference() { this._removeReference(-this._referenceCount); } _resetFrameIndices() { for (var i = 0, n = this._currentFrameIndices.length; i < n; i++) this._currentFrameIndices[i] = -1; } addScript(type) { var script = new type(); this._scripts = this._scripts || []; this._scripts.push(script); return script; } getScript(type) { if (this._scripts) { for (var i = 0, n = this._scripts.length; i < n; i++) { var script = this._scripts[i]; if (script instanceof type) return script; } } return null; } getScripts(type) { var coms; if (this._scripts) { for (var i = 0, n = this._scripts.length; i < n; i++) { var script = this._scripts[i]; if (script instanceof type) { coms = coms || []; coms.push(script); } } } return coms; } cloneTo(destObject) { var dest = destObject; dest.name = this.name; dest.speed = this.speed; dest.clipStart = this.clipStart; dest.clipEnd = this.clipEnd; dest.clip = this._clip; } clone() { var dest = new AnimatorState(); this.cloneTo(dest); return dest; } } class KeyframeNodeOwner { constructor() { this.indexInList = -1; this.referenceCount = 0; this.updateMark = -1; this.type = -1; this.fullPath = null; this.propertyOwner = null; this.property = null; this.defaultValue = null; this.value = null; this.crossFixedValue = null; } saveCrossFixedValue() { var pro = this.propertyOwner; if (pro) { switch (this.type) { case 0: this.crossFixedValue = this.value; break; case 1: case 3: case 4: this.value.cloneTo(this.crossFixedValue); break; case 2: this.value.cloneTo(this.crossFixedValue); break; default: throw "Animator:unknown type."; } } } } class Animator extends Laya.Component { constructor() { super(); this._keyframeNodeOwners = []; this._linkAvatarSpritesData = {}; this._linkAvatarSprites = []; this._renderableSprites = []; this.cullingMode = Animator.CULLINGMODE_CULLCOMPLETELY; this._controllerLayers = []; this._linkSprites = {}; this._speed = 1.0; this._keyframeNodeOwnerMap = {}; this._updateMark = 0; } static _update(scene) { var pool = scene._animatorPool; var elements = pool.elements; for (var i = 0, n = pool.length; i < n; i++) { var animator = elements[i]; (animator && animator.enabled) && (animator._update()); } } get speed() { return this._speed; } set speed(value) { this._speed = value; } _linkToSprites(linkSprites) { for (var k in linkSprites) { var nodeOwner = this.owner; var path = linkSprites[k]; for (var j = 0, m = path.length; j < m; j++) { var p = path[j]; if (p === "") { break; } else { nodeOwner = nodeOwner.getChildByName(p); if (!nodeOwner) break; } } (nodeOwner) && (this.linkSprite3DToAvatarNode(k, nodeOwner)); } } _addKeyframeNodeOwner(clipOwners, node, propertyOwner) { var nodeIndex = node._indexInList; var fullPath = node.fullPath; var keyframeNodeOwner = this._keyframeNodeOwnerMap[fullPath]; if (keyframeNodeOwner) { keyframeNodeOwner.referenceCount++; clipOwners[nodeIndex] = keyframeNodeOwner; } else { var property = propertyOwner; for (var i = 0, n = node.propertyCount; i < n; i++) { property = property[node.getPropertyByIndex(i)]; if (!property) break; } keyframeNodeOwner = this._keyframeNodeOwnerMap[fullPath] = new KeyframeNodeOwner(); keyframeNodeOwner.fullPath = fullPath; keyframeNodeOwner.indexInList = this._keyframeNodeOwners.length; keyframeNodeOwner.referenceCount = 1; keyframeNodeOwner.propertyOwner = propertyOwner; var propertyCount = node.propertyCount; var propertys = []; for (i = 0; i < propertyCount; i++) propertys[i] = node.getPropertyByIndex(i); keyframeNodeOwner.property = propertys; keyframeNodeOwner.type = node.type; if (property) { if (node.type === 0) { keyframeNodeOwner.defaultValue = property; } else { var defaultValue = new property.constructor(); property.cloneTo(defaultValue); keyframeNodeOwner.defaultValue = defaultValue; keyframeNodeOwner.value = new property.constructor(); keyframeNodeOwner.crossFixedValue = new property.constructor(); } } this._keyframeNodeOwners.push(keyframeNodeOwner); clipOwners[nodeIndex] = keyframeNodeOwner; } } _removeKeyframeNodeOwner(nodeOwners, node) { var fullPath = node.fullPath; var keyframeNodeOwner = this._keyframeNodeOwnerMap[fullPath]; if (keyframeNodeOwner) { keyframeNodeOwner.referenceCount--; if (keyframeNodeOwner.referenceCount === 0) { delete this._keyframeNodeOwnerMap[fullPath]; this._keyframeNodeOwners.splice(this._keyframeNodeOwners.indexOf(keyframeNodeOwner), 1); } nodeOwners[node._indexInList] = null; } } _getOwnersByClip(clipStateInfo) { var frameNodes = clipStateInfo._clip._nodes; var frameNodesCount = frameNodes.count; var nodeOwners = clipStateInfo._nodeOwners; nodeOwners.length = frameNodesCount; for (var i = 0; i < frameNodesCount; i++) { var node = frameNodes.getNodeByIndex(i); var property = this._avatar ? this._avatarNodeMap[this._avatar._rootNode.name] : this.owner; for (var j = 0, m = node.ownerPathCount; j < m; j++) { var ownPat = node.getOwnerPathByIndex(j); if (ownPat === "") { break; } else { property = property.getChildByName(ownPat); if (!property) break; } } if (property) { var propertyOwner = node.propertyOwner; (propertyOwner) && (property = property[propertyOwner]); property && this._addKeyframeNodeOwner(nodeOwners, node, property); } } } _updatePlayer(animatorState, playState, elapsedTime, islooping) { var clipDuration = animatorState._clip._duration * (animatorState.clipEnd - animatorState.clipStart); var lastElapsedTime = playState._elapsedTime; var elapsedPlaybackTime = lastElapsedTime + elapsedTime; playState._lastElapsedTime = lastElapsedTime; playState._elapsedTime = elapsedPlaybackTime; var normalizedTime = elapsedPlaybackTime / clipDuration; playState._normalizedTime = normalizedTime; var playTime = normalizedTime % 1.0; playState._normalizedPlayTime = playTime < 0 ? playTime + 1.0 : playTime; playState._duration = clipDuration; var scripts = animatorState._scripts; if ((!islooping && elapsedPlaybackTime >= clipDuration)) { playState._finish = true; playState._elapsedTime = clipDuration; playState._normalizedPlayTime = 1.0; if (scripts) { for (var i = 0, n = scripts.length; i < n; i++) scripts[i].onStateExit(); } return; } if (scripts) { for (i = 0, n = scripts.length; i < n; i++) scripts[i].onStateUpdate(); } } _eventScript(scripts, events, eventIndex, endTime, front) { if (front) { for (var n = events.length; eventIndex < n; eventIndex++) { var event = events[eventIndex]; if (event.time <= endTime) { for (var j = 0, m = scripts.length; j < m; j++) { var script = scripts[j]; var fun = script[event.eventName]; (fun) && (fun.apply(script, event.params)); } } else { break; } } } else { for (; eventIndex >= 0; eventIndex--) { event = events[eventIndex]; if (event.time >= endTime) { for (j = 0, m = scripts.length; j < m; j++) { script = scripts[j]; fun = script[event.eventName]; (fun) && (fun.apply(script, event.params)); } } else { break; } } } return eventIndex; } _updateEventScript(stateInfo, playStateInfo) { var scripts = this.owner._scripts; if (scripts) { var clip = stateInfo._clip; var events = clip._animationEvents; var clipDuration = clip._duration; var elapsedTime = playStateInfo._elapsedTime; var time = elapsedTime % clipDuration; var loopCount = Math.abs(Math.floor(elapsedTime / clipDuration) - Math.floor(playStateInfo._lastElapsedTime / clipDuration)); var frontPlay = playStateInfo._elapsedTime >= playStateInfo._lastElapsedTime; if (playStateInfo._lastIsFront !== frontPlay) { if (frontPlay) playStateInfo._playEventIndex++; else playStateInfo._playEventIndex--; playStateInfo._lastIsFront = frontPlay; } if (frontPlay) { playStateInfo._playEventIndex = this._eventScript(scripts, events, playStateInfo._playEventIndex, loopCount > 0 ? clipDuration : time, true); for (var i = 0, n = loopCount - 1; i < n; i++) this._eventScript(scripts, events, 0, clipDuration, true); (loopCount > 0 && time > 0) && (playStateInfo._playEventIndex = this._eventScript(scripts, events, 0, time, true)); } else { playStateInfo._playEventIndex = this._eventScript(scripts, events, playStateInfo._playEventIndex, loopCount > 0 ? 0 : time, false); var eventIndex = events.length - 1; for (i = 0, n = loopCount - 1; i < n; i++) this._eventScript(scripts, events, eventIndex, 0, false); (loopCount > 0 && time > 0) && (playStateInfo._playEventIndex = this._eventScript(scripts, events, eventIndex, time, false)); } } } _updateClipDatas(animatorState, addtive, playStateInfo, scale) { var clip = animatorState._clip; var clipDuration = clip._duration; var curPlayTime = animatorState.clipStart * clipDuration + playStateInfo._normalizedPlayTime * playStateInfo._duration; var currentFrameIndices = animatorState._currentFrameIndices; var frontPlay = playStateInfo._elapsedTime > playStateInfo._lastElapsedTime; clip._evaluateClipDatasRealTime(clip._nodes, curPlayTime, currentFrameIndices, addtive, frontPlay, animatorState._realtimeDatas); } _applyFloat(pro, proName, nodeOwner, additive, weight, isFirstLayer, data) { if (nodeOwner.updateMark === this._updateMark) { if (additive) { pro[proName] += weight * data; } else { var oriValue = pro[proName]; pro[proName] = oriValue + weight * (data - oriValue); } } else { if (isFirstLayer) { if (additive) pro[proName] = nodeOwner.defaultValue + data; else pro[proName] = data; } else { if (additive) { pro[proName] = nodeOwner.defaultValue + weight * (data); } else { var defValue = nodeOwner.defaultValue; pro[proName] = defValue + weight * (data - defValue); } } } } _applyPositionAndRotationEuler(nodeOwner, additive, weight, isFirstLayer, data, out) { if (nodeOwner.updateMark === this._updateMark) { if (additive) { out.x += weight * data.x; out.y += weight * data.y; out.z += weight * data.z; } else { var oriX = out.x; var oriY = out.y; var oriZ = out.z; out.x = oriX + weight * (data.x - oriX); out.y = oriY + weight * (data.y - oriY); out.z = oriZ + weight * (data.z - oriZ); } } else { if (isFirstLayer) { if (additive) { var defValue = nodeOwner.defaultValue; out.x = defValue.x + data.x; out.y = defValue.y + data.y; out.z = defValue.z + data.z; } else { out.x = data.x; out.y = data.y; out.z = data.z; } } else { defValue = nodeOwner.defaultValue; if (additive) { out.x = defValue.x + weight * data.x; out.y = defValue.y + weight * data.y; out.z = defValue.z + weight * data.z; } else { var defX = defValue.x; var defY = defValue.y; var defZ = defValue.z; out.x = defX + weight * (data.x - defX); out.y = defY + weight * (data.y - defY); out.z = defZ + weight * (data.z - defZ); } } } } _applyRotation(nodeOwner, additive, weight, isFirstLayer, clipRot, localRotation) { if (nodeOwner.updateMark === this._updateMark) { if (additive) { var tempQuat = Animator._tempQuaternion1; Utils3D.quaternionWeight(clipRot, weight, tempQuat); tempQuat.normalize(tempQuat); Quaternion.multiply(localRotation, tempQuat, localRotation); } else { Quaternion.lerp(localRotation, clipRot, weight, localRotation); } } else { if (isFirstLayer) { if (additive) { var defaultRot = nodeOwner.defaultValue; Quaternion.multiply(defaultRot, clipRot, localRotation); } else { localRotation.x = clipRot.x; localRotation.y = clipRot.y; localRotation.z = clipRot.z; localRotation.w = clipRot.w; } } else { defaultRot = nodeOwner.defaultValue; if (additive) { tempQuat = Animator._tempQuaternion1; Utils3D.quaternionWeight(clipRot, weight, tempQuat); tempQuat.normalize(tempQuat); Quaternion.multiply(defaultRot, tempQuat, localRotation); } else { Quaternion.lerp(defaultRot, clipRot, weight, localRotation); } } } } _applyScale(nodeOwner, additive, weight, isFirstLayer, clipSca, localScale) { if (nodeOwner.updateMark === this._updateMark) { if (additive) { var scale = Animator._tempVector31; Utils3D.scaleWeight(clipSca, weight, scale); localScale.x = localScale.x * scale.x; localScale.y = localScale.y * scale.y; localScale.z = localScale.z * scale.z; } else { Utils3D.scaleBlend(localScale, clipSca, weight, localScale); } } else { if (isFirstLayer) { if (additive) { var defaultSca = nodeOwner.defaultValue; localScale.x = defaultSca.x * clipSca.x; localScale.y = defaultSca.y * clipSca.y; localScale.z = defaultSca.z * clipSca.z; } else { localScale.x = clipSca.x; localScale.y = clipSca.y; localScale.z = clipSca.z; } } else { defaultSca = nodeOwner.defaultValue; if (additive) { scale = Animator._tempVector31; Utils3D.scaleWeight(clipSca, weight, scale); localScale.x = defaultSca.x * scale.x; localScale.y = defaultSca.y * scale.y; localScale.z = defaultSca.z * scale.z; } else { Utils3D.scaleBlend(defaultSca, clipSca, weight, localScale); } } } } _applyCrossData(nodeOwner, additive, weight, isFirstLayer, srcValue, desValue, crossWeight) { var pro = nodeOwner.propertyOwner; if (pro) { switch (nodeOwner.type) { case 0: var proPat = nodeOwner.property; var m = proPat.length - 1; for (var j = 0; j < m; j++) { pro = pro[proPat[j]]; if (!pro) break; } var crossValue = srcValue + crossWeight * (desValue - srcValue); nodeOwner.value = crossValue; this._applyFloat(pro, proPat[m], nodeOwner, additive, weight, isFirstLayer, crossValue); break; case 1: var localPos = pro.localPosition; var position = nodeOwner.value; var srcX = srcValue.x, srcY = srcValue.y, srcZ = srcValue.z; position.x = srcX + crossWeight * (desValue.x - srcX); position.y = srcY + crossWeight * (desValue.y - srcY); position.z = srcZ + crossWeight * (desValue.z - srcZ); this._applyPositionAndRotationEuler(nodeOwner, additive, weight, isFirstLayer, position, localPos); pro.localPosition = localPos; break; case 2: var localRot = pro.localRotation; var rotation = nodeOwner.value; Quaternion.lerp(srcValue, desValue, crossWeight, rotation); this._applyRotation(nodeOwner, additive, weight, isFirstLayer, rotation, localRot); pro.localRotation = localRot; break; case 3: var localSca = pro.localScale; var scale = nodeOwner.value; Utils3D.scaleBlend(srcValue, desValue, crossWeight, scale); this._applyScale(nodeOwner, additive, weight, isFirstLayer, scale, localSca); pro.localScale = localSca; break; case 4: var localEuler = pro.localRotationEuler; var rotationEuler = nodeOwner.value; srcX = srcValue.x, srcY = srcValue.y, srcZ = srcValue.z; rotationEuler.x = srcX + crossWeight * (desValue.x - srcX); rotationEuler.y = srcY + crossWeight * (desValue.y - srcY); rotationEuler.z = srcZ + crossWeight * (desValue.z - srcZ); this._applyPositionAndRotationEuler(nodeOwner, additive, weight, isFirstLayer, rotationEuler, localEuler); pro.localRotationEuler = localEuler; break; } nodeOwner.updateMark = this._updateMark; } } _setClipDatasToNode(stateInfo, additive, weight, isFirstLayer) { var realtimeDatas = stateInfo._realtimeDatas; var nodes = stateInfo._clip._nodes; var nodeOwners = stateInfo._nodeOwners; for (var i = 0, n = nodes.count; i < n; i++) { var nodeOwner = nodeOwners[i]; if (nodeOwner) { var pro = nodeOwner.propertyOwner; if (pro) { switch (nodeOwner.type) { case 0: var proPat = nodeOwner.property; var m = proPat.length - 1; for (var j = 0; j < m; j++) { pro = pro[proPat[j]]; if (!pro) break; } this._applyFloat(pro, proPat[m], nodeOwner, additive, weight, isFirstLayer, realtimeDatas[i]); break; case 1: var localPos = pro.localPosition; this._applyPositionAndRotationEuler(nodeOwner, additive, weight, isFirstLayer, realtimeDatas[i], localPos); pro.localPosition = localPos; break; case 2: var localRot = pro.localRotation; this._applyRotation(nodeOwner, additive, weight, isFirstLayer, realtimeDatas[i], localRot); pro.localRotation = localRot; break; case 3: var localSca = pro.localScale; this._applyScale(nodeOwner, additive, weight, isFirstLayer, realtimeDatas[i], localSca); pro.localScale = localSca; break; case 4: var localEuler = pro.localRotationEuler; this._applyPositionAndRotationEuler(nodeOwner, additive, weight, isFirstLayer, realtimeDatas[i], localEuler); pro.localRotationEuler = localEuler; break; } nodeOwner.updateMark = this._updateMark; } } } } _setCrossClipDatasToNode(controllerLayer, srcState, destState, crossWeight, isFirstLayer) { var nodeOwners = controllerLayer._crossNodesOwners; var ownerCount = controllerLayer._crossNodesOwnersCount; var additive = controllerLayer.blendingMode !== AnimatorControllerLayer.BLENDINGMODE_OVERRIDE; var weight = controllerLayer.defaultWeight; var destRealtimeDatas = destState._realtimeDatas; var destDataIndices = controllerLayer._destCrossClipNodeIndices; var destNodeOwners = destState._nodeOwners; var srcRealtimeDatas = srcState._realtimeDatas; var srcDataIndices = controllerLayer._srcCrossClipNodeIndices; var srcNodeOwners = srcState._nodeOwners; for (var i = 0; i < ownerCount; i++) { var nodeOwner = nodeOwners[i]; if (nodeOwner) { var srcIndex = srcDataIndices[i]; var destIndex = destDataIndices[i]; var srcValue = srcIndex !== -1 ? srcRealtimeDatas[srcIndex] : destNodeOwners[destIndex].defaultValue; var desValue = destIndex !== -1 ? destRealtimeDatas[destIndex] : srcNodeOwners[srcIndex].defaultValue; this._applyCrossData(nodeOwner, additive, weight, isFirstLayer, srcValue, desValue, crossWeight); } } } _setFixedCrossClipDatasToNode(controllerLayer, destState, crossWeight, isFirstLayer) { var nodeOwners = controllerLayer._crossNodesOwners; var ownerCount = controllerLayer._crossNodesOwnersCount; var additive = controllerLayer.blendingMode !== AnimatorControllerLayer.BLENDINGMODE_OVERRIDE; var weight = controllerLayer.defaultWeight; var destRealtimeDatas = destState._realtimeDatas; var destDataIndices = controllerLayer._destCrossClipNodeIndices; for (var i = 0; i < ownerCount; i++) { var nodeOwner = nodeOwners[i]; if (nodeOwner) { var destIndex = destDataIndices[i]; var srcValue = nodeOwner.crossFixedValue; var desValue = destIndex !== -1 ? destRealtimeDatas[destIndex] : nodeOwner.defaultValue; this._applyCrossData(nodeOwner, additive, weight, isFirstLayer, srcValue, desValue, crossWeight); } } } _revertDefaultKeyframeNodes(clipStateInfo) { var nodeOwners = clipStateInfo._nodeOwners; for (var i = 0, n = nodeOwners.length; i < n; i++) { var nodeOwner = nodeOwners[i]; if (nodeOwner) { var pro = nodeOwner.propertyOwner; if (pro) { switch (nodeOwner.type) { case 0: var proPat = nodeOwner.property; var m = proPat.length - 1; for (var j = 0; j < m; j++) { pro = pro[proPat[j]]; if (!pro) break; } pro[proPat[m]] = nodeOwner.defaultValue; break; case 1: var locPos = pro.localPosition; var def = nodeOwner.defaultValue; locPos.x = def.x; locPos.y = def.y; locPos.z = def.z; pro.localPosition = locPos; break; case 2: var locRot = pro.localRotation; var defQua = nodeOwner.defaultValue; locRot.x = defQua.x; locRot.y = defQua.y; locRot.z = defQua.z; locRot.w = defQua.w; pro.localRotation = locRot; break; case 3: var locSca = pro.localScale; def = nodeOwner.defaultValue; locSca.x = def.x; locSca.y = def.y; locSca.z = def.z; pro.localScale = locSca; break; case 4: var locEul = pro.localRotationEuler; def = nodeOwner.defaultValue; locEul.x = def.x; locEul.y = def.y; locEul.z = def.z; pro.localRotationEuler = locEul; break; default: throw "Animator:unknown type."; } } } } } _onAdded() { var parent = this.owner._parent; this.owner._setHierarchyAnimator(this, parent ? parent._hierarchyAnimator : null); this.owner._changeAnimatorToLinkSprite3DNoAvatar(this, true, []); } _onDestroy() { for (var i = 0, n = this._controllerLayers.length; i < n; i++) this._controllerLayers[i]._removeReference(); var parent = this.owner._parent; this.owner._clearHierarchyAnimator(this, parent ? parent._hierarchyAnimator : null); } _onEnable() { this.owner._scene._animatorPool.add(this); for (var i = 0, n = this._controllerLayers.length; i < n; i++) { if (this._controllerLayers[i].playOnWake) { var defaultClip = this.getDefaultState(i); (defaultClip) && (this.play(null, i, 0)); } } } _onDisable() { this.owner._scene._animatorPool.remove(this); } _handleSpriteOwnersBySprite(isLink, path, sprite) { for (var i = 0, n = this._controllerLayers.length; i < n; i++) { var clipStateInfos = this._controllerLayers[i]._states; for (var j = 0, m = clipStateInfos.length; j < m; j++) { var clipStateInfo = clipStateInfos[j]; var clip = clipStateInfo._clip; var nodePath = path.join("/"); var ownersNodes = clip._nodesMap[nodePath]; if (ownersNodes) { var nodeOwners = clipStateInfo._nodeOwners; for (var k = 0, p = ownersNodes.length; k < p; k++) { if (isLink) this._addKeyframeNodeOwner(nodeOwners, ownersNodes[k], sprite); else this._removeKeyframeNodeOwner(nodeOwners, ownersNodes[k]); } } } } } _parse(data) { var avatarData = data.avatar; if (avatarData) { this.avatar = Laya.Loader.getRes(avatarData.path); var linkSprites = avatarData.linkSprites; this._linkSprites = linkSprites; this._linkToSprites(linkSprites); } var clipPaths = data.clipPaths; var play = data.playOnWake; var layersData = data.layers; for (var i = 0; i < layersData.length; i++) { var layerData = layersData[i]; var animatorLayer = new AnimatorControllerLayer(layerData.name); if (i === 0) animatorLayer.defaultWeight = 1.0; else animatorLayer.defaultWeight = layerData.weight; var blendingModeData = layerData.blendingMode; (blendingModeData) && (animatorLayer.blendingMode = blendingModeData); this.addControllerLayer(animatorLayer); var states = layerData.states; for (var j = 0, m = states.length; j < m; j++) { var state = states[j]; var clipPath = state.clipPath; if (clipPath) { var name = state.name; var motion; motion = Laya.Loader.getRes(clipPath); if (motion) { var animatorState = new AnimatorState(); animatorState.name = name; animatorState.clip = motion; animatorLayer.addState(animatorState); (j === 0) && (this.getControllerLayer(i).defaultState = animatorState); } } } (play !== undefined) && (animatorLayer.playOnWake = play); } var cullingModeData = data.cullingMode; (cullingModeData !== undefined) && (this.cullingMode = cullingModeData); } _update() { var timer = this.owner._scene.timer; var delta = timer._delta / 1000.0; if (this._speed === 0 || delta === 0) return; var needRender; if (this.cullingMode === Animator.CULLINGMODE_CULLCOMPLETELY) { needRender = false; for (var i = 0, n = this._renderableSprites.length; i < n; i++) { if (this._renderableSprites[i]._render.isRender) { needRender = true; break; } } } else { needRender = true; } this._updateMark++; var timerScale = timer.scale; for (i = 0, n = this._controllerLayers.length; i < n; i++) { var controllerLayer = this._controllerLayers[i]; var playStateInfo = controllerLayer._playStateInfo; var crossPlayStateInfo = controllerLayer._crossPlayStateInfo; addtive = controllerLayer.blendingMode !== AnimatorControllerLayer.BLENDINGMODE_OVERRIDE; switch (controllerLayer._playType) { case 0: var animatorState = playStateInfo._currentState; var clip = animatorState._clip; var speed = this._speed * animatorState.speed; var finish = playStateInfo._finish; finish || this._updatePlayer(animatorState, playStateInfo, delta * speed, clip.islooping); if (needRender) { var addtive = controllerLayer.blendingMode !== AnimatorControllerLayer.BLENDINGMODE_OVERRIDE; this._updateClipDatas(animatorState, addtive, playStateInfo, timerScale * speed); this._setClipDatasToNode(animatorState, addtive, controllerLayer.defaultWeight, i === 0); finish || this._updateEventScript(animatorState, playStateInfo); } break; case 1: animatorState = playStateInfo._currentState; clip = animatorState._clip; var crossState = controllerLayer._crossPlayState; var crossClip = crossState._clip; var crossDuratuion = controllerLayer._crossDuration; var startPlayTime = crossPlayStateInfo._startPlayTime; var crossClipDuration = crossClip._duration - startPlayTime; var crossScale = crossDuratuion > crossClipDuration ? crossClipDuration / crossDuratuion : 1.0; var crossSpeed = this._speed * crossState.speed; this._updatePlayer(crossState, crossPlayStateInfo, delta * crossScale * crossSpeed, crossClip.islooping); var crossWeight = ((crossPlayStateInfo._elapsedTime - startPlayTime) / crossScale) / crossDuratuion; if (crossWeight >= 1.0) { if (needRender) { this._updateClipDatas(crossState, addtive, crossPlayStateInfo, timerScale * crossSpeed); this._setClipDatasToNode(crossState, addtive, controllerLayer.defaultWeight, i === 0); controllerLayer._playType = 0; playStateInfo._currentState = crossState; crossPlayStateInfo._cloneTo(playStateInfo); } } else { if (!playStateInfo._finish) { speed = this._speed * animatorState.speed; this._updatePlayer(animatorState, playStateInfo, delta * speed, clip.islooping); if (needRender) this._updateClipDatas(animatorState, addtive, playStateInfo, timerScale * speed); } if (needRender) { this._updateClipDatas(crossState, addtive, crossPlayStateInfo, timerScale * crossScale * crossSpeed); this._setCrossClipDatasToNode(controllerLayer, animatorState, crossState, crossWeight, i === 0); } } if (needRender) { this._updateEventScript(animatorState, playStateInfo); this._updateEventScript(crossState, crossPlayStateInfo); } break; case 2: crossState = controllerLayer._crossPlayState; crossClip = crossState._clip; crossDuratuion = controllerLayer._crossDuration; startPlayTime = crossPlayStateInfo._startPlayTime; crossClipDuration = crossClip._duration - startPlayTime; crossScale = crossDuratuion > crossClipDuration ? crossClipDuration / crossDuratuion : 1.0; crossSpeed = this._speed * crossState.speed; this._updatePlayer(crossState, crossPlayStateInfo, delta * crossScale * crossSpeed, crossClip.islooping); if (needRender) { crossWeight = ((crossPlayStateInfo._elapsedTime - startPlayTime) / crossScale) / crossDuratuion; if (crossWeight >= 1.0) { this._updateClipDatas(crossState, addtive, crossPlayStateInfo, timerScale * crossSpeed); this._setClipDatasToNode(crossState, addtive, 1.0, i === 0); controllerLayer._playType = 0; playStateInfo._currentState = crossState; crossPlayStateInfo._cloneTo(playStateInfo); } else { this._updateClipDatas(crossState, addtive, crossPlayStateInfo, timerScale * crossScale * crossSpeed); this._setFixedCrossClipDatasToNode(controllerLayer, crossState, crossWeight, i === 0); } this._updateEventScript(crossState, crossPlayStateInfo); } break; } } if (needRender) { if (this._avatar) { Laya.Render.supportWebGLPlusAnimation && this._updateAnimationNodeWorldMatix(this._animationNodeLocalPositions, this._animationNodeLocalRotations, this._animationNodeLocalScales, this._animationNodeWorldMatrixs, this._animationNodeParentIndices); this._updateAvatarNodesToSprite(); } } } _cloneTo(dest) { var animator = dest; animator.avatar = this.avatar; animator.cullingMode = this.cullingMode; for (var i = 0, n = this._controllerLayers.length; i < n; i++) { var controllLayer = this._controllerLayers[i]; animator.addControllerLayer(controllLayer.clone()); var animatorStates = controllLayer._states; for (var j = 0, m = animatorStates.length; j < m; j++) { var state = animatorStates[j].clone(); var cloneLayer = animator.getControllerLayer(i); cloneLayer.addState(state); (j == 0) && (cloneLayer.defaultState = state); } } animator._linkSprites = this._linkSprites; animator._linkToSprites(this._linkSprites); } getDefaultState(layerIndex = 0) { var controllerLayer = this._controllerLayers[layerIndex]; return controllerLayer.defaultState; } addState(state, layerIndex = 0) { var controllerLayer = this._controllerLayers[layerIndex]; controllerLayer.addState(state); console.warn("Animator:this function is discard,please use animatorControllerLayer.addState() instead."); } removeState(state, layerIndex = 0) { var controllerLayer = this._controllerLayers[layerIndex]; controllerLayer.removeState(state); console.warn("Animator:this function is discard,please use animatorControllerLayer.removeState() instead."); } addControllerLayer(controllderLayer) { this._controllerLayers.push(controllderLayer); controllderLayer._animator = this; controllderLayer._addReference(); var states = controllderLayer._states; for (var i = 0, n = states.length; i < n; i++) this._getOwnersByClip(states[i]); } getControllerLayer(layerInex = 0) { return this._controllerLayers[layerInex]; } play(name = null, layerIndex = 0, normalizedTime = Number.NEGATIVE_INFINITY) { var controllerLayer = this._controllerLayers[layerIndex]; if (controllerLayer) { var defaultState = controllerLayer.defaultState; if (!name && !defaultState) throw new Error("Animator:must have default clip value,please set clip property."); var playStateInfo = controllerLayer._playStateInfo; var curPlayState = playStateInfo._currentState; var animatorState = name ? controllerLayer._statesMap[name] : defaultState; var clipDuration = animatorState._clip._duration; if (curPlayState !== animatorState) { if (normalizedTime !== Number.NEGATIVE_INFINITY) playStateInfo._resetPlayState(clipDuration * normalizedTime); else playStateInfo._resetPlayState(0.0); (curPlayState !== null && curPlayState !== animatorState) && (this._revertDefaultKeyframeNodes(curPlayState)); controllerLayer._playType = 0; playStateInfo._currentState = animatorState; } else { if (normalizedTime !== Number.NEGATIVE_INFINITY) { playStateInfo._resetPlayState(clipDuration * normalizedTime); controllerLayer._playType = 0; } } var scripts = animatorState._scripts; if (scripts) { for (var i = 0, n = scripts.length; i < n; i++) scripts[i].onStateEnter(); } } else { console.warn("Invalid layerIndex " + layerIndex + "."); } } crossFade(name, transitionDuration, layerIndex = 0, normalizedTime = Number.NEGATIVE_INFINITY) { var controllerLayer = this._controllerLayers[layerIndex]; if (controllerLayer) { var destAnimatorState = controllerLayer._statesMap[name]; if (destAnimatorState) { var playType = controllerLayer._playType; if (playType === -1) { this.play(name, layerIndex, normalizedTime); return; } var crossPlayStateInfo = controllerLayer._crossPlayStateInfo; var crossNodeOwners = controllerLayer._crossNodesOwners; var crossNodeOwnerIndicesMap = controllerLayer._crossNodesOwnersIndicesMap; var srcAnimatorState = controllerLayer._playStateInfo._currentState; var destNodeOwners = destAnimatorState._nodeOwners; var destCrossClipNodeIndices = controllerLayer._destCrossClipNodeIndices; var destClip = destAnimatorState._clip; var destNodes = destClip._nodes; var destNodesMap = destClip._nodesDic; switch (playType) { case 0: var srcNodeOwners = srcAnimatorState._nodeOwners; var scrCrossClipNodeIndices = controllerLayer._srcCrossClipNodeIndices; var srcClip = srcAnimatorState._clip; var srcNodes = srcClip._nodes; var srcNodesMap = srcClip._nodesDic; controllerLayer._playType = 1; var crossMark = ++controllerLayer._crossMark; var crossCount = controllerLayer._crossNodesOwnersCount = 0; for (var i = 0, n = srcNodes.count; i < n; i++) { var srcNode = srcNodes.getNodeByIndex(i); var srcIndex = srcNode._indexInList; var srcNodeOwner = srcNodeOwners[srcIndex]; if (srcNodeOwner) { var srcFullPath = srcNode.fullPath; scrCrossClipNodeIndices[crossCount] = srcIndex; var destNode = destNodesMap[srcFullPath]; if (destNode) destCrossClipNodeIndices[crossCount] = destNode._indexInList; else destCrossClipNodeIndices[crossCount] = -1; crossNodeOwnerIndicesMap[srcFullPath] = crossMark; crossNodeOwners[crossCount] = srcNodeOwner; crossCount++; } } for (i = 0, n = destNodes.count; i < n; i++) { destNode = destNodes.getNodeByIndex(i); var destIndex = destNode._indexInList; var destNodeOwner = destNodeOwners[destIndex]; if (destNodeOwner) { var destFullPath = destNode.fullPath; if (!srcNodesMap[destFullPath]) { scrCrossClipNodeIndices[crossCount] = -1; destCrossClipNodeIndices[crossCount] = destIndex; crossNodeOwnerIndicesMap[destFullPath] = crossMark; crossNodeOwners[crossCount] = destNodeOwner; crossCount++; } } } break; case 1: case 2: controllerLayer._playType = 2; for (i = 0, n = crossNodeOwners.length; i < n; i++) { var nodeOwner = crossNodeOwners[i]; nodeOwner.saveCrossFixedValue(); destNode = destNodesMap[nodeOwner.fullPath]; if (destNode) destCrossClipNodeIndices[i] = destNode._indexInList; else destCrossClipNodeIndices[i] = -1; } crossCount = controllerLayer._crossNodesOwnersCount; crossMark = controllerLayer._crossMark; for (i = 0, n = destNodes.count; i < n; i++) { destNode = destNodes.getNodeByIndex(i); destIndex = destNode._indexInList; destNodeOwner = destNodeOwners[destIndex]; if (destNodeOwner) { destFullPath = destNode.fullPath; if (crossNodeOwnerIndicesMap[destFullPath] !== crossMark) { destCrossClipNodeIndices[crossCount] = destIndex; crossNodeOwnerIndicesMap[destFullPath] = crossMark; nodeOwner = destNodeOwners[destIndex]; crossNodeOwners[crossCount] = nodeOwner; nodeOwner.saveCrossFixedValue(); crossCount++; } } } break; default: } controllerLayer._crossNodesOwnersCount = crossCount; controllerLayer._crossPlayState = destAnimatorState; controllerLayer._crossDuration = srcAnimatorState._clip._duration * transitionDuration; if (normalizedTime !== Number.NEGATIVE_INFINITY) crossPlayStateInfo._resetPlayState(destClip._duration * normalizedTime); else crossPlayStateInfo._resetPlayState(0.0); var scripts = destAnimatorState._scripts; if (scripts) { for (i = 0, n = scripts.length; i < n; i++) scripts[i].onStateEnter(); } } else { console.warn("Invalid name " + layerIndex + "."); } } else { console.warn("Invalid layerIndex " + layerIndex + "."); } } getCurrentAnimatorPlayState(layerInex = 0) { return this._controllerLayers[layerInex]._playStateInfo; } get avatar() { return this._avatar; } set avatar(value) { if (this._avatar !== value) { this._avatar = value; if (value) { this._getAvatarOwnersAndInitDatasAsync(); this.owner._changeHierarchyAnimatorAvatar(this, value); } else { var parent = this.owner._parent; this.owner._changeHierarchyAnimatorAvatar(this, parent ? parent._hierarchyAnimator._avatar : null); } } } _isLinkSpriteToAnimationNodeData(sprite, nodeName, isLink) { var linkSprites = this._linkAvatarSpritesData[nodeName]; if (isLink) { linkSprites || (this._linkAvatarSpritesData[nodeName] = linkSprites = []); linkSprites.push(sprite); } else { var index = linkSprites.indexOf(sprite); linkSprites.splice(index, 1); } } _getAvatarOwnersAndInitDatasAsync() { for (var i = 0, n = this._controllerLayers.length; i < n; i++) { var clipStateInfos = this._controllerLayers[i]._states; for (var j = 0, m = clipStateInfos.length; j < m; j++) this._getOwnersByClip(clipStateInfos[j]); } this._avatar._cloneDatasToAnimator(this); for (var k in this._linkAvatarSpritesData) { var sprites = this._linkAvatarSpritesData[k]; if (sprites) { for (var c = 0, p = sprites.length; c < p; c++) this._isLinkSpriteToAnimationNode(sprites[c], k, true); } } } _isLinkSpriteToAnimationNode(sprite, nodeName, isLink) { if (this._avatar) { var node = this._avatarNodeMap[nodeName]; if (node) { if (isLink) { sprite._transform._dummy = node.transform; this._linkAvatarSprites.push(sprite); var nodeTransform = node.transform; var spriteTransform = sprite.transform; if (!spriteTransform.owner.isStatic && nodeTransform) { var spriteWorldMatrix = spriteTransform.worldMatrix; var ownParTra = this.owner._transform._parent; if (ownParTra) { Utils3D.matrix4x4MultiplyMFM(ownParTra.worldMatrix, nodeTransform.getWorldMatrix(), spriteWorldMatrix); } else { var sprWorE = spriteWorldMatrix.elements; var nodWorE = nodeTransform.getWorldMatrix(); for (var i = 0; i < 16; i++) sprWorE[i] = nodWorE[i]; } spriteTransform.worldMatrix = spriteWorldMatrix; } } else { sprite._transform._dummy = null; this._linkAvatarSprites.splice(this._linkAvatarSprites.indexOf(sprite), 1); } } } } _updateAvatarNodesToSprite() { for (var i = 0, n = this._linkAvatarSprites.length; i < n; i++) { var sprite = this._linkAvatarSprites[i]; var nodeTransform = sprite.transform._dummy; var spriteTransform = sprite.transform; if (!spriteTransform.owner.isStatic && nodeTransform) { var spriteWorldMatrix = spriteTransform.worldMatrix; var ownTra = this.owner._transform; Utils3D.matrix4x4MultiplyMFM(ownTra.worldMatrix, nodeTransform.getWorldMatrix(), spriteWorldMatrix); spriteTransform.worldMatrix = spriteWorldMatrix; } } } linkSprite3DToAvatarNode(nodeName, sprite3D) { this._isLinkSpriteToAnimationNodeData(sprite3D, nodeName, true); this._isLinkSpriteToAnimationNode(sprite3D, nodeName, true); return true; } unLinkSprite3DToAvatarNode(sprite3D) { var dummy = sprite3D.transform._dummy; if (dummy) { var nodeName = dummy._owner.name; this._isLinkSpriteToAnimationNodeData(sprite3D, nodeName, false); this._isLinkSpriteToAnimationNode(sprite3D, nodeName, false); return true; } else { return false; } } _updateAnimationNodeWorldMatix(localPositions, localRotations, localScales, worldMatrixs, parentIndices) { Laya.LayaGL.instance.updateAnimationNodeWorldMatix(localPositions, localRotations, localScales, parentIndices, worldMatrixs); } } Animator._tempVector30 = new Vector3(); Animator._tempVector31 = new Vector3(); Animator._tempQuaternion0 = new Quaternion(); Animator._tempQuaternion1 = new Quaternion(); Animator.CULLINGMODE_ALWAYSANIMATE = 0; Animator.CULLINGMODE_CULLCOMPLETELY = 2; class PostProcessRenderContext { constructor() { this.source = null; this.destination = null; this.camera = null; this.compositeShaderData = null; this.command = null; this.deferredReleaseTextures = []; } } class RenderContext3D { constructor() { this.invertY = false; } } RenderContext3D._instance = new RenderContext3D(); class RenderTexture extends Laya.BaseTexture { constructor(width, height, format = Laya.RenderTextureFormat.R8G8B8, depthStencilFormat = Laya.RenderTextureDepthFormat.DEPTH_16) { super(format, false); this._inPool = false; this._isCameraTarget = false; this._glTextureType = Laya.LayaGL.instance.TEXTURE_2D; this._width = width; this._height = height; this._depthStencilFormat = depthStencilFormat; this._mipmapCount = 1; this._create(width, height); } static get currentActive() { return RenderTexture._currentActive; } static createFromPool(width, height, format = Laya.RenderTextureFormat.R8G8B8, depthStencilFormat = Laya.RenderTextureDepthFormat.DEPTH_16) { var tex; for (var i = 0, n = RenderTexture._pool.length; i < n; i++) { tex = RenderTexture._pool[i]; if (tex._width == width && tex._height == height && tex._format == format && tex._depthStencilFormat == depthStencilFormat) { tex._inPool = false; var end = RenderTexture._pool[n - 1]; RenderTexture._pool[i] = end; RenderTexture._pool.length -= 1; return tex; } } tex = new RenderTexture(width, height, format, depthStencilFormat); tex.lock = true; return tex; } static recoverToPool(renderTexture) { if (renderTexture._inPool) return; RenderTexture._pool.push(renderTexture); renderTexture._inPool = true; } get depthStencilFormat() { return this._depthStencilFormat; } get defaulteTexture() { return Laya.Texture2D.grayTexture; } _create(width, height) { var gl = Laya.LayaGL.instance; var gl2 = gl; var glTextureType = this._glTextureType; var layaGPU = Laya.LayaGL.layaGPUInstance; var isWebGL2 = layaGPU._isWebGL2; var format = this._format; this._frameBuffer = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, this._frameBuffer); if (format !== Laya.RenderTextureFormat.Depth && format !== Laya.RenderTextureFormat.ShadowMap) { Laya.WebGLContext.bindTexture(gl, glTextureType, this._glTexture); switch (format) { case Laya.RenderTextureFormat.R8G8B8: if (isWebGL2) gl2.texStorage2D(glTextureType, this._mipmapCount, gl2.RGB8, width, height); else gl.texImage2D(glTextureType, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, null); break; case Laya.RenderTextureFormat.R8G8B8A8: if (isWebGL2) gl2.texStorage2D(glTextureType, this._mipmapCount, gl2.RGBA8, width, height); else gl.texImage2D(glTextureType, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); break; case Laya.RenderTextureFormat.Alpha8: if (isWebGL2) gl2.texStorage2D(glTextureType, 0, gl2.R8, width, height); else gl.texImage2D(glTextureType, 0, gl.ALPHA, width, height, 0, gl.ALPHA, gl.UNSIGNED_BYTE, null); break; case Laya.RenderTextureFormat.R16G16B16A16: if (isWebGL2) gl2.texStorage2D(glTextureType, this._mipmapCount, gl2.RGBA16F, width, height); else gl.texImage2D(glTextureType, 0, gl.RGBA, width, height, 0, gl.RGBA, layaGPU._oesTextureHalfFloat.HALF_FLOAT_OES, null); break; } gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._glTexture, 0); } if (format == Laya.RenderTextureFormat.Depth || format == Laya.RenderTextureFormat.ShadowMap) { Laya.WebGLContext.bindTexture(gl, glTextureType, this._glTexture); switch (this._depthStencilFormat) { case Laya.RenderTextureDepthFormat.DEPTH_16: if (isWebGL2) gl2.texStorage2D(glTextureType, this._mipmapCount, gl2.DEPTH_COMPONENT16, width, height); else gl.texImage2D(glTextureType, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this._glTexture, 0); break; case Laya.RenderTextureDepthFormat.DEPTHSTENCIL_24_8: if (isWebGL2) gl2.texStorage2D(glTextureType, this._mipmapCount, gl2.DEPTH24_STENCIL8, width, height); else gl.texImage2D(glTextureType, 0, gl.DEPTH_STENCIL, width, height, 0, gl.DEPTH_STENCIL, layaGPU._webgl_depth_texture.UNSIGNED_INT_24_8_WEBGL, null); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, this._glTexture, 0); break; default: throw "RenderTexture: depth format RenderTexture must use depthFormat with DEPTH_16 and DEPTHSTENCIL_16_8."; } if (isWebGL2 && format == Laya.RenderTextureFormat.ShadowMap) gl2.texParameteri(glTextureType, gl2.TEXTURE_COMPARE_MODE, gl2.COMPARE_REF_TO_TEXTURE); } else { if (this._depthStencilFormat !== Laya.RenderTextureDepthFormat.DEPTHSTENCIL_NONE) { this._depthStencilBuffer = gl.createRenderbuffer(); gl.bindRenderbuffer(gl.RENDERBUFFER, this._depthStencilBuffer); switch (this._depthStencilFormat) { case Laya.RenderTextureDepthFormat.DEPTH_16: gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this._depthStencilBuffer); break; case Laya.RenderTextureDepthFormat.STENCIL_8: gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, width, height); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, this._depthStencilBuffer); break; case Laya.RenderTextureDepthFormat.DEPTHSTENCIL_24_8: gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this._depthStencilBuffer); break; default: throw "RenderTexture: unkonw depth format."; } gl.bindRenderbuffer(gl.RENDERBUFFER, null); } } gl.bindFramebuffer(gl.FRAMEBUFFER, null); this._setWarpMode(gl.TEXTURE_WRAP_S, this._wrapModeU); this._setWarpMode(gl.TEXTURE_WRAP_T, this._wrapModeV); this._setFilterMode(this._filterMode); this._setAnisotropy(this._anisoLevel); this._readyed = true; this._activeResource(); this._setGPUMemory(width * height * 4); } _start() { var gl = Laya.LayaGL.instance; gl.bindFramebuffer(gl.FRAMEBUFFER, this._frameBuffer); RenderTexture._currentActive = this; (this._isCameraTarget) && (RenderContext3D._instance.invertY = true); this._readyed = false; } _end() { var gl = Laya.LayaGL.instance; gl.bindFramebuffer(gl.FRAMEBUFFER, null); RenderTexture._currentActive = null; (this._isCameraTarget) && (RenderContext3D._instance.invertY = false); this._readyed = true; } getData(x, y, width, height, out) { if (Laya.Render.isConchApp && window.conchConfig.threadMode == 2) { throw "native 2 thread mode use getDataAsync"; } var gl = Laya.LayaGL.instance; gl.bindFramebuffer(gl.FRAMEBUFFER, this._frameBuffer); var canRead = (gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE); if (!canRead) { gl.bindFramebuffer(gl.FRAMEBUFFER, null); return null; } gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, out); gl.bindFramebuffer(gl.FRAMEBUFFER, null); return out; } _disposeResource() { if (this._frameBuffer) { var gl = Laya.LayaGL.instance; gl.deleteTexture(this._glTexture); gl.deleteFramebuffer(this._frameBuffer); gl.deleteRenderbuffer(this._depthStencilBuffer); this._glTexture = null; this._frameBuffer = null; this._depthStencilBuffer = null; this._setGPUMemory(0); } } getDataAsync(x, y, width, height, callBack) { var gl = Laya.LayaGL.instance; gl.bindFramebuffer(gl.FRAMEBUFFER, this._frameBuffer); gl.readPixelsAsync(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, function (data) { callBack(new Uint8Array(data)); }); gl.bindFramebuffer(gl.FRAMEBUFFER, null); } } RenderTexture._pool = []; class DefineDatas { constructor() { this._mask = []; this._length = 0; } _intersectionDefineDatas(define) { var unionMask = define._mask; var mask = this._mask; for (var i = this._length - 1; i >= 0; i--) { var value = mask[i] & unionMask[i]; if (value == 0 && i == this._length - 1) this._length--; else mask[i] = value; } } add(define) { var index = define._index; var size = index + 1; var mask = this._mask; var maskStart = this._length; if (maskStart < size) { (mask.length < size) && (mask.length = size); for (; maskStart < index; maskStart++) mask[maskStart] = 0; mask[index] = define._value; this._length = size; } else { if (size > this._length) { mask[index] = define._value; this._length = size; } else { mask[index] |= define._value; } } } remove(define) { var index = define._index; var mask = this._mask; var endIndex = this._length - 1; if (index > endIndex) return; var newValue = mask[index] & ~define._value; if (index == endIndex && newValue === 0) this._length--; else mask[index] = newValue; } addDefineDatas(define) { var addMask = define._mask; var size = define._length; var mask = this._mask; var maskStart = mask.length; if (maskStart < size) { mask.length = size; for (var i = 0; i < maskStart; i++) mask[i] |= addMask[i]; for (; maskStart < size; maskStart++) mask[maskStart] = addMask[maskStart]; this._length = size; } else { for (var i = 0; i < size; i++) mask[i] |= addMask[i]; this._length = Math.max(this._length, size); } } removeDefineDatas(define) { var removeMask = define._mask; var mask = this._mask; var endIndex = this._length - 1; for (var i = define._length - 1; i >= 0; i--) { if (i > endIndex) continue; var newValue = mask[i] & ~removeMask[i]; if (i == endIndex && newValue === 0) { endIndex--; this._length--; } else { mask[i] = newValue; } } } has(define) { var index = define._index; if (index >= this._length) return false; return (this._mask[index] & define._value) !== 0; } clear() { this._length = 0; } cloneTo(destObject) { var destDefineData = destObject; var destMask = destDefineData._mask; var mask = this._mask; var count = this._length; destMask.length = count; for (var i = 0; i < count; i++) destMask[i] = mask[i]; destDefineData._length = count; } clone() { var dest = new DefineDatas(); this.cloneTo(dest); return dest; } } class ShaderDefine { constructor(index, value) { this._index = index; this._value = value; } } class ShaderVariant { constructor(shader, subShaderIndex, passIndex, defines) { this._subShaderIndex = 0; this._passIndex = 0; this.setValue(shader, subShaderIndex, passIndex, defines); } get shader() { return this._shader; } get subShaderIndex() { return this._subShaderIndex; } get passIndex() { return this._passIndex; } get defineNames() { return this._defineNames; } setValue(shader, subShaderIndex, passIndex, defineNames) { if (shader) { var subShader = shader.getSubShaderAt(subShaderIndex); if (subShader) { var pass = subShader._passes[passIndex]; if (pass) { var validDefine = pass._validDefine; for (var i = 0, n = defineNames.length; i < n; i++) { var defname = defineNames[i]; if (!validDefine.has(ILaya3D.Shader3D.getDefineByName(defname))) throw `ShaderVariantInfo:Invalid defineName ${defname} in ${shader._name} subShaderIndex of ${subShaderIndex} passIndex of ${passIndex}.`; } } else { throw `ShaderVariantInfo:Shader don't have passIndex of ${passIndex}.`; } } else { throw `ShaderVariantInfo:Shader don't have subShaderIndex of ${subShaderIndex}.`; } } else { throw `ShaderVariantInfo:Shader can't be null.`; } this._shader = shader; this._subShaderIndex = subShaderIndex; this._passIndex = passIndex; this._defineNames = defineNames; } equal(other) { if (this._shader !== other._shader || this._subShaderIndex !== other._subShaderIndex || this._passIndex !== other._passIndex) return false; var defines = this._defineNames; var otherDefines = other._defineNames; if (defines.length !== otherDefines.length) return false; for (var i = 0, n = this._defineNames.length; i < n; i++) { if (defines[i] !== otherDefines[i]) return false; } return true; } clone() { var dest = new ShaderVariant(this._shader, this._subShaderIndex, this._passIndex, this._defineNames.slice()); return dest; } } class ShaderVariantCollection { constructor() { this._allCompiled = false; this._variants = []; } get allCompiled() { return this._allCompiled; } get variantCount() { return this._variants.length; } add(variant) { for (var i = 0, n = this._variants.length; i < n; i++) { if (this._variants[i].equal(variant)) return false; } this._variants.push(variant.clone()); this._allCompiled = false; return true; } remove(variant) { for (var i = 0, n = this._variants.length; i < n; i++) { if (this._variants[i].equal(variant)) { this._variants.splice(i, 1); return true; } } return false; } contatins(variant) { for (var i = 0, n = this._variants.length; i < n; i++) { if (this._variants[i].equal(variant)) return true; } return false; } getByIndex(index) { return this._variants[index]; } clear() { this._variants.length = 0; } compile() { if (!this._allCompiled) { var variants = this._variants; for (var i = 0, n = variants.length; i < n; i++) { var variant = variants[i]; ILaya3D.Shader3D.compileShaderByDefineNames(variant._shader._name, variant._subShaderIndex, variant._passIndex, variant._defineNames); } this._allCompiled = true; } } } class Shader3D { constructor(name, attributeMap, uniformMap, enableInstancing) { this._attributeMap = null; this._uniformMap = null; this._enableInstancing = false; this._subShaders = []; this._name = name; this._attributeMap = attributeMap; this._uniformMap = uniformMap; this._enableInstancing = enableInstancing; } static _getNamesByDefineData(defineData, out) { var maskMap = Shader3D._maskMap; var mask = defineData._mask; out.length = 0; for (var i = 0, n = defineData._length; i < n; i++) { var subMaskMap = maskMap[i]; var subMask = mask[i]; for (var j = 0; j < 32; j++) { var d = 1 << j; if (subMask > 0 && d > subMask) break; if (subMask & d) out.push(subMaskMap[d]); } } } static getDefineByName(name) { var define = Shader3D._defineMap[name]; if (!define) { var maskMap = Shader3D._maskMap; var counter = Shader3D._defineCounter; var index = Math.floor(counter / 32); var value = 1 << counter % 32; define = new ShaderDefine(index, value); Shader3D._defineMap[name] = define; if (index == maskMap.length) { maskMap.length++; maskMap[index] = {}; } maskMap[index][value] = name; Shader3D._defineCounter++; } return define; } static propertyNameToID(name) { if (Shader3D._propertyNameMap[name] != null) { return Shader3D._propertyNameMap[name]; } else { var id = Shader3D._propertyNameCounter++; Shader3D._propertyNameMap[name] = id; return id; } } static addInclude(fileName, txt) { txt = txt.replace(Laya.ShaderCompile._clearCR, ""); Laya.ShaderCompile.addInclude(fileName, txt); } static compileShaderByDefineNames(shaderName, subShaderIndex, passIndex, defineNames) { var shader = Shader3D.find(shaderName); if (shader) { var subShader = shader.getSubShaderAt(subShaderIndex); if (subShader) { var pass = subShader._passes[passIndex]; if (pass) { var compileDefineDatas = Shader3D._compileDefineDatas; compileDefineDatas.clear(); for (var i = 0, n = defineNames.length; i < n; i++) compileDefineDatas.add(Shader3D.getDefineByName(defineNames[i])); pass.withCompile(compileDefineDatas); } else { console.warn("Shader3D: unknown passIndex."); } } else { console.warn("Shader3D: unknown subShaderIndex."); } } else { console.warn("Shader3D: unknown shader name."); } } static add(name, attributeMap = null, uniformMap = null, enableInstancing = false) { return Shader3D._preCompileShader[name] = new Shader3D(name, attributeMap, uniformMap, enableInstancing); } static find(name) { return Shader3D._preCompileShader[name]; } get name() { return this._name; } addSubShader(subShader) { this._subShaders.push(subShader); subShader._owner = this; } getSubShaderAt(index) { return this._subShaders[index]; } static compileShader(shaderName, subShaderIndex, passIndex, ...defineMask) { var shader = Shader3D.find(shaderName); if (shader) { var subShader = shader.getSubShaderAt(subShaderIndex); if (subShader) { var pass = subShader._passes[passIndex]; if (pass) { var compileDefineDatas = Shader3D._compileDefineDatas; var mask = compileDefineDatas._mask; mask.length = 0; for (var i = 0, n = defineMask.length; i < n; i++) mask.push(defineMask[i]); compileDefineDatas._length = defineMask.length; pass.withCompile(compileDefineDatas); } else { console.warn("Shader3D: unknown passIndex."); } } else { console.warn("Shader3D: unknown subShaderIndex."); } } else { console.warn("Shader3D: unknown shader name."); } } } Shader3D._compileDefineDatas = new DefineDatas(); Shader3D.RENDER_STATE_CULL = 0; Shader3D.RENDER_STATE_BLEND = 1; Shader3D.RENDER_STATE_BLEND_SRC = 2; Shader3D.RENDER_STATE_BLEND_DST = 3; Shader3D.RENDER_STATE_BLEND_SRC_RGB = 4; Shader3D.RENDER_STATE_BLEND_DST_RGB = 5; Shader3D.RENDER_STATE_BLEND_SRC_ALPHA = 6; Shader3D.RENDER_STATE_BLEND_DST_ALPHA = 7; Shader3D.RENDER_STATE_BLEND_CONST_COLOR = 8; Shader3D.RENDER_STATE_BLEND_EQUATION = 9; Shader3D.RENDER_STATE_BLEND_EQUATION_RGB = 10; Shader3D.RENDER_STATE_BLEND_EQUATION_ALPHA = 11; Shader3D.RENDER_STATE_DEPTH_TEST = 12; Shader3D.RENDER_STATE_DEPTH_WRITE = 13; Shader3D.PERIOD_CUSTOM = 0; Shader3D.PERIOD_MATERIAL = 1; Shader3D.PERIOD_SPRITE = 2; Shader3D.PERIOD_CAMERA = 3; Shader3D.PERIOD_SCENE = 4; Shader3D._propertyNameCounter = 0; Shader3D._propertyNameMap = {}; Shader3D._defineCounter = 0; Shader3D._defineMap = {}; Shader3D._preCompileShader = {}; Shader3D._maskMap = []; Shader3D.debugMode = false; Shader3D.debugShaderVariantCollection = new ShaderVariantCollection(); class ShaderData { constructor(ownerResource = null) { this._ownerResource = null; this._data = null; this._defineDatas = new DefineDatas(); this._runtimeCopyValues = []; this._ownerResource = ownerResource; this._initData(); } _initData() { this._data = new Object(); } getData() { return this._data; } addDefine(define) { this._defineDatas.add(define); } removeDefine(define) { this._defineDatas.remove(define); } hasDefine(define) { return this._defineDatas.has(define); } clearDefine() { this._defineDatas.clear(); } getBool(index) { return this._data[index]; } setBool(index, value) { this._data[index] = value; } getInt(index) { return this._data[index]; } setInt(index, value) { this._data[index] = value; } getNumber(index) { return this._data[index]; } setNumber(index, value) { this._data[index] = value; } getVector2(index) { return this._data[index]; } setVector2(index, value) { this._data[index] = value; } getVector3(index) { return this._data[index]; } setVector3(index, value) { this._data[index] = value; } getVector(index) { return this._data[index]; } setVector(index, value) { this._data[index] = value; } getQuaternion(index) { return this._data[index]; } setQuaternion(index, value) { this._data[index] = value; } getMatrix4x4(index) { return this._data[index]; } setMatrix4x4(index, value) { this._data[index] = value; } getBuffer(shaderIndex) { return this._data[shaderIndex]; } setBuffer(index, value) { this._data[index] = value; } setTexture(index, value) { var lastValue = this._data[index]; this._data[index] = value; if (this._ownerResource && this._ownerResource.referenceCount > 0) { (lastValue) && (lastValue._removeReference()); (value) && (value._addReference()); } } getTexture(index) { return this._data[index]; } setAttribute(index, value) { this._data[index] = value; } getAttribute(index) { return this._data[index]; } getLength() { return this._data.length; } setLength(value) { this._data.length = value; } cloneTo(destObject) { var dest = destObject; var destData = dest._data; for (var k in this._data) { var value = this._data[k]; if (value != null) { if (typeof (value) == 'number') { destData[k] = value; } else if (typeof (value) == 'number') { destData[k] = value; } else if (typeof (value) == "boolean") { destData[k] = value; } else if (value instanceof Vector2) { var v2 = (destData[k]) || (destData[k] = new Vector2()); value.cloneTo(v2); destData[k] = v2; } else if (value instanceof Vector3) { var v3 = (destData[k]) || (destData[k] = new Vector3()); value.cloneTo(v3); destData[k] = v3; } else if (value instanceof Vector4) { var v4 = (destData[k]) || (destData[k] = new Vector4()); value.cloneTo(v4); destData[k] = v4; } else if (value instanceof Matrix4x4) { var mat = (destData[k]) || (destData[k] = new Matrix4x4()); value.cloneTo(mat); destData[k] = mat; } else if (value instanceof Laya.BaseTexture) { destData[k] = value; } } } this._defineDatas.cloneTo(dest._defineDatas); } clone() { var dest = new ShaderData(); this.cloneTo(dest); return dest; } cloneToForNative(destObject) { var dest = destObject; var diffSize = this._int32Data.length - dest._int32Data.length; if (diffSize > 0) { dest.needRenewArrayBufferForNative(this._int32Data.length); } dest._int32Data.set(this._int32Data, 0); var destData = dest._nativeArray; var dataCount = this._nativeArray.length; destData.length = dataCount; for (var i = 0; i < dataCount; i++) { var value = this._nativeArray[i]; if (value) { if (typeof (value) == 'number') { destData[i] = value; dest.setNumber(i, value); } else if (typeof (value) == 'number') { destData[i] = value; dest.setInt(i, value); } else if (typeof (value) == "boolean") { destData[i] = value; dest.setBool(i, value); } else if (value instanceof Vector2) { var v2 = (destData[i]) || (destData[i] = new Vector2()); value.cloneTo(v2); destData[i] = v2; dest.setVector2(i, v2); } else if (value instanceof Vector3) { var v3 = (destData[i]) || (destData[i] = new Vector3()); value.cloneTo(v3); destData[i] = v3; dest.setVector3(i, v3); } else if (value instanceof Vector4) { var v4 = (destData[i]) || (destData[i] = new Vector4()); value.cloneTo(v4); destData[i] = v4; dest.setVector(i, v4); } else if (value instanceof Matrix4x4) { var mat = (destData[i]) || (destData[i] = new Matrix4x4()); value.cloneTo(mat); destData[i] = mat; dest.setMatrix4x4(i, mat); } else if (value instanceof Laya.BaseTexture) { destData[i] = value; dest.setTexture(i, value); } } } this._defineDatas.cloneTo(dest._defineDatas); } _initDataForNative() { var length = 8; this._frameCount = -1; this._runtimeCopyValues.length = 0; this._nativeArray = []; this._data = new ArrayBuffer(length * 4); this._int32Data = new Int32Array(this._data); this._float32Data = new Float32Array(this._data); Laya.LayaGL.instance.createArrayBufferRef(this._data, Laya.LayaGL.ARRAY_BUFFER_TYPE_DATA, true); } needRenewArrayBufferForNative(index) { if (index >= this._int32Data.length) { var nByteLen = (index + 1) * 4; var pre = this._int32Data; var preConchRef = this._data["conchRef"]; var prePtrID = this._data["_ptrID"]; this._data = new ArrayBuffer(nByteLen); this._int32Data = new Int32Array(this._data); this._float32Data = new Float32Array(this._data); this._data["conchRef"] = preConchRef; this._data["_ptrID"] = prePtrID; pre && this._int32Data.set(pre, 0); var layagl = Laya.LayaGL.instance; if (layagl.updateArrayBufferRef) { layagl.updateArrayBufferRef(this._data['_ptrID'], preConchRef.isSyncToRender(), this._data); } else { window.conch.updateArrayBufferRef(this._data['_ptrID'], preConchRef.isSyncToRender(), this._data); } } } getDataForNative() { return this._nativeArray; } getIntForNative(index) { return this._int32Data[index]; } setIntForNative(index, value) { this.needRenewArrayBufferForNative(index); this._int32Data[index] = value; this._nativeArray[index] = value; } getBoolForNative(index) { return this._int32Data[index] == 1; } setBoolForNative(index, value) { this.needRenewArrayBufferForNative(index); this._int32Data[index] = value ? 1 : 0; this._nativeArray[index] = value; } getNumberForNative(index) { return this._float32Data[index]; } setNumberForNative(index, value) { this.needRenewArrayBufferForNative(index); this._float32Data[index] = value; this._nativeArray[index] = value; } getMatrix4x4ForNative(index) { return this._nativeArray[index]; } setMatrix4x4ForNative(index, value) { this.needRenewArrayBufferForNative(index); this._nativeArray[index] = value; var nPtrID = this.setReferenceForNative(value.elements); this._int32Data[index] = nPtrID; } getVectorForNative(index) { return this._nativeArray[index]; } setVectorForNative(index, value) { this.needRenewArrayBufferForNative(index); this._nativeArray[index] = value; if (!value.elements) { value.forNativeElement(); } var nPtrID = this.setReferenceForNative(value.elements); this._int32Data[index] = nPtrID; } getVector2ForNative(index) { return this._nativeArray[index]; } setVector2ForNative(index, value) { this.needRenewArrayBufferForNative(index); this._nativeArray[index] = value; if (!value.elements) { value.forNativeElement(); } var nPtrID = this.setReferenceForNative(value.elements); this._int32Data[index] = nPtrID; } getVector3ForNative(index) { return this._nativeArray[index]; } setVector3ForNative(index, value) { this.needRenewArrayBufferForNative(index); this._nativeArray[index] = value; if (!value.elements) { value.forNativeElement(); } var nPtrID = this.setReferenceForNative(value.elements); this._int32Data[index] = nPtrID; } getQuaternionForNative(index) { return this._nativeArray[index]; } setQuaternionForNative(index, value) { this.needRenewArrayBufferForNative(index); this._nativeArray[index] = value; if (!value.elements) { value.forNativeElement(); } var nPtrID = this.setReferenceForNative(value.elements); this._int32Data[index] = nPtrID; } getBufferForNative(shaderIndex) { return this._nativeArray[shaderIndex]; } setBufferForNative(index, value) { this.needRenewArrayBufferForNative(index); this._nativeArray[index] = value; var nPtrID = this.setReferenceForNative(value); this._int32Data[index] = nPtrID; } getAttributeForNative(index) { return this._nativeArray[index]; } setAttributeForNative(index, value) { this._nativeArray[index] = value; if (!value["_ptrID"]) { Laya.LayaGL.instance.createArrayBufferRef(value, Laya.LayaGL.ARRAY_BUFFER_TYPE_DATA, true); } Laya.LayaGL.instance.syncBufferToRenderThread(value); this._int32Data[index] = value["_ptrID"]; } getTextureForNative(index) { return this._nativeArray[index]; } setTextureForNative(index, value) { if (!value) return; this.needRenewArrayBufferForNative(index); var lastValue = this._nativeArray[index]; this._nativeArray[index] = value; var glTexture = value._getSource() || value.defaulteTexture._getSource(); this._int32Data[index] = glTexture.id; if (this._ownerResource && this._ownerResource.referenceCount > 0) { (lastValue) && (lastValue._removeReference()); (value) && (value._addReference()); } } setReferenceForNative(value) { this.clearRuntimeCopyArray(); var nRefID = 0; var nPtrID = 0; if (ShaderData._SET_RUNTIME_VALUE_MODE_REFERENCE_) { Laya.LayaGL.instance.createArrayBufferRefs(value, Laya.LayaGL.ARRAY_BUFFER_TYPE_DATA, true, Laya.LayaGL.ARRAY_BUFFER_REF_REFERENCE); nRefID = 0; nPtrID = value.getPtrID(nRefID); } else { Laya.LayaGL.instance.createArrayBufferRefs(value, Laya.LayaGL.ARRAY_BUFFER_TYPE_DATA, true, Laya.LayaGL.ARRAY_BUFFER_REF_COPY); nRefID = value.getRefNum() - 1; nPtrID = value.getPtrID(nRefID); this._runtimeCopyValues.push({ "obj": value, "refID": nRefID, "ptrID": nPtrID }); } Laya.LayaGL.instance.syncBufferToRenderThread(value, nRefID); return nPtrID; } static setRuntimeValueMode(bReference) { ShaderData._SET_RUNTIME_VALUE_MODE_REFERENCE_ = bReference; } clearRuntimeCopyArray() { var currentFrame = Laya.Stat.loopCount; if (this._frameCount != currentFrame) { this._frameCount = currentFrame; for (var i = 0, n = this._runtimeCopyValues.length; i < n; i++) { var obj = this._runtimeCopyValues[i]; obj.obj.clearRefNum(); } this._runtimeCopyValues.length = 0; } } } ShaderData._SET_RUNTIME_VALUE_MODE_REFERENCE_ = true; class PostProcess { constructor() { this._compositeShader = Shader3D.find("PostProcessComposite"); this._compositeShaderData = new ShaderData(); this._effects = []; this._context = null; this._context = new PostProcessRenderContext(); this._context.compositeShaderData = this._compositeShaderData; } static __init__() { PostProcess.SHADERDEFINE_BLOOM_LOW = Shader3D.getDefineByName("BLOOM_LOW"); PostProcess.SHADERDEFINE_BLOOM = Shader3D.getDefineByName("BLOOM"); PostProcess.SHADERDEFINE_FINALPASS = Shader3D.getDefineByName("FINALPASS"); } _init(camera, command) { this._context.camera = camera; this._context.command = command; } _render() { var noteValue = ShaderData._SET_RUNTIME_VALUE_MODE_REFERENCE_; Laya.ILaya.Render.supportWebGLPlusRendering && ShaderData.setRuntimeValueMode(false); var camera = this._context.camera; var viewport = camera.viewport; var screenTexture = RenderTexture.createFromPool(RenderContext3D.clientWidth, RenderContext3D.clientHeight, camera._getRenderTextureFormat(), Laya.RenderTextureDepthFormat.DEPTHSTENCIL_NONE); var cameraTarget = camera._internalRenderTexture; this._context.command.clear(); this._context.source = screenTexture; this._context.destination = cameraTarget; this._context.compositeShaderData.clearDefine(); this._context.command.blitScreenTriangle(cameraTarget, screenTexture); this._context.compositeShaderData.setTexture(PostProcess.SHADERVALUE_AUTOEXPOSURETEX, Laya.Texture2D.whiteTexture); for (var i = 0, n = this._effects.length; i < n; i++) this._effects[i].render(this._context); this._compositeShaderData.addDefine(PostProcess.SHADERDEFINE_FINALPASS); var offScreenTex = camera._offScreenRenderTexture; var dest = offScreenTex ? offScreenTex : null; this._context.destination = dest; var canvasWidth = camera._getCanvasWidth(), canvasHeight = camera._getCanvasHeight(); camera._screenOffsetScale.setValue(viewport.x / canvasWidth, viewport.y / canvasHeight, viewport.width / canvasWidth, viewport.height / canvasHeight); this._context.command.blitScreenTriangle(this._context.source, dest, camera._screenOffsetScale, this._compositeShader, this._compositeShaderData); RenderTexture.recoverToPool(screenTexture); var tempRenderTextures = this._context.deferredReleaseTextures; for (i = 0, n = tempRenderTextures.length; i < n; i++) RenderTexture.recoverToPool(tempRenderTextures[i]); tempRenderTextures.length = 0; Laya.ILaya.Render.supportWebGLPlusRendering && ShaderData.setRuntimeValueMode(noteValue); } addEffect(effect) { this._effects.push(effect); } removeEffect(effect) { var index = this._effects.indexOf(effect); if (index !== -1) this._effects.splice(index, 1); } } PostProcess.SHADERVALUE_MAINTEX = Shader3D.propertyNameToID("u_MainTex"); PostProcess.SHADERVALUE_BLOOMTEX = Shader3D.propertyNameToID("u_BloomTex"); PostProcess.SHADERVALUE_AUTOEXPOSURETEX = Shader3D.propertyNameToID("u_AutoExposureTex"); PostProcess.SHADERVALUE_BLOOM_DIRTTEX = Shader3D.propertyNameToID("u_Bloom_DirtTex"); PostProcess.SHADERVALUE_BLOOMTEX_TEXELSIZE = Shader3D.propertyNameToID("u_BloomTex_TexelSize"); PostProcess.SHADERVALUE_BLOOM_DIRTTILEOFFSET = Shader3D.propertyNameToID("u_Bloom_DirtTileOffset"); PostProcess.SHADERVALUE_BLOOM_SETTINGS = Shader3D.propertyNameToID("u_Bloom_Settings"); PostProcess.SHADERVALUE_BLOOM_COLOR = Shader3D.propertyNameToID("u_Bloom_Color"); class AnimationTransform3D extends Laya.EventDispatcher { constructor(owner, localPosition = null, localRotation = null, localScale = null, worldMatrix = null) { super(); this._owner = owner; this._children = []; this._localMatrix = new Float32Array(16); if (Laya.Render.supportWebGLPlusAnimation) { this._localPosition = new ConchVector3(0, 0, 0, localPosition); this._localRotation = new ConchQuaternion(0, 0, 0, 1, localRotation); this._localScale = new ConchVector3(0, 0, 0, localScale); this._worldMatrix = worldMatrix; } else { this._localPosition = new Vector3(); this._localRotation = new Quaternion(); this._localScale = new Vector3(); this._worldMatrix = new Float32Array(16); } this._localQuaternionUpdate = false; this._locaEulerlUpdate = false; this._localUpdate = false; this._worldUpdate = true; } _getlocalMatrix() { if (this._localUpdate) { Utils3D._createAffineTransformationArray(this._localPosition, this._localRotation, this._localScale, this._localMatrix); this._localUpdate = false; } return this._localMatrix; } _onWorldTransform() { if (!this._worldUpdate) { this._worldUpdate = true; this.event(Laya.Event.TRANSFORM_CHANGED); for (var i = 0, n = this._children.length; i < n; i++) this._children[i]._onWorldTransform(); } } get localPosition() { return this._localPosition; } set localPosition(value) { this._localPosition = value; this._localUpdate = true; this._onWorldTransform(); } get localRotation() { if (this._localQuaternionUpdate) { var euler = this._localRotationEuler; Quaternion.createFromYawPitchRoll(euler.y / AnimationTransform3D._angleToRandin, euler.x / AnimationTransform3D._angleToRandin, euler.z / AnimationTransform3D._angleToRandin, this._localRotation); this._localQuaternionUpdate = false; } return this._localRotation; } set localRotation(value) { this._localRotation = value; this._locaEulerlUpdate = true; this._localQuaternionUpdate = false; this._localUpdate = true; this._onWorldTransform(); } get localScale() { return this._localScale; } set localScale(value) { this._localScale = value; this._localUpdate = true; this._onWorldTransform(); } get localRotationEuler() { if (this._locaEulerlUpdate) { this._localRotation.getYawPitchRoll(AnimationTransform3D._tempVector3); var euler = AnimationTransform3D._tempVector3; var localRotationEuler = this._localRotationEuler; localRotationEuler.x = euler.y * AnimationTransform3D._angleToRandin; localRotationEuler.y = euler.x * AnimationTransform3D._angleToRandin; localRotationEuler.z = euler.z * AnimationTransform3D._angleToRandin; this._locaEulerlUpdate = false; } return this._localRotationEuler; } set localRotationEuler(value) { this._localRotationEuler = value; this._locaEulerlUpdate = false; this._localQuaternionUpdate = true; this._localUpdate = true; this._onWorldTransform(); } getWorldMatrix() { if (!Laya.Render.supportWebGLPlusAnimation && this._worldUpdate) { if (this._parent != null) { Utils3D.matrix4x4MultiplyFFF(this._parent.getWorldMatrix(), this._getlocalMatrix(), this._worldMatrix); } else { var e = this._worldMatrix; e[1] = e[2] = e[3] = e[4] = e[6] = e[7] = e[8] = e[9] = e[11] = e[12] = e[13] = e[14] = 0; e[0] = e[5] = e[10] = e[15] = 1; } this._worldUpdate = false; } if (Laya.Render.supportWebGLPlusAnimation && this._worldUpdate) { this._worldUpdate = false; } return this._worldMatrix; } setParent(value) { if (this._parent !== value) { if (this._parent) { var parentChilds = this._parent._children; var index = parentChilds.indexOf(this); parentChilds.splice(index, 1); } if (value) { value._children.push(this); (value) && (this._onWorldTransform()); } this._parent = value; } } } AnimationTransform3D._tempVector3 = new Vector3(); AnimationTransform3D._angleToRandin = 180 / Math.PI; class AnimationNode { constructor(localPosition = null, localRotation = null, localScale = null, worldMatrix = null) { this._children = []; this.transform = new AnimationTransform3D(this, localPosition, localRotation, localScale, worldMatrix); } addChild(child) { child._parent = this; child.transform.setParent(this.transform); this._children.push(child); } removeChild(child) { var index = this._children.indexOf(child); (index !== -1) && (this._children.splice(index, 1)); } getChildByName(name) { for (var i = 0, n = this._children.length; i < n; i++) { var child = this._children[i]; if (child.name === name) return child; } return null; } getChildByIndex(index) { return this._children[index]; } getChildCount() { return this._children.length; } cloneTo(destObject) { var destNode = destObject; destNode.name = this.name; for (var i = 0, n = this._children.length; i < n; i++) { var child = this._children[i]; var destChild = child.clone(); destNode.addChild(destChild); var transform = child.transform; var destTransform = destChild.transform; var destLocalPosition = destTransform.localPosition; var destLocalRotation = destTransform.localRotation; var destLocalScale = destTransform.localScale; transform.localPosition.cloneTo(destLocalPosition); transform.localRotation.cloneTo(destLocalRotation); transform.localScale.cloneTo(destLocalScale); destTransform.localPosition = destLocalPosition; destTransform.localRotation = destLocalRotation; destTransform.localScale = destLocalScale; } } clone() { var dest = new AnimationNode(); this.cloneTo(dest); return dest; } _cloneNative(localPositions, localRotations, localScales, animationNodeWorldMatrixs, animationNodeParentIndices, parentIndex, avatar) { var curID = avatar._nativeCurCloneCount; animationNodeParentIndices[curID] = parentIndex; var localPosition = new Float32Array(localPositions.buffer, curID * 3 * 4, 3); var localRotation = new Float32Array(localRotations.buffer, curID * 4 * 4, 4); var localScale = new Float32Array(localScales.buffer, curID * 3 * 4, 3); var worldMatrix = new Float32Array(animationNodeWorldMatrixs.buffer, curID * 16 * 4, 16); var dest = new AnimationNode(localPosition, localRotation, localScale, worldMatrix); dest._worldMatrixIndex = curID; this._cloneToNative(dest, localPositions, localRotations, localScales, animationNodeWorldMatrixs, animationNodeParentIndices, curID, avatar); return dest; } _cloneToNative(destObject, localPositions, localRotations, localScales, animationNodeWorldMatrixs, animationNodeParentIndices, parentIndex, avatar) { var destNode = destObject; destNode.name = this.name; for (var i = 0, n = this._children.length; i < n; i++) { var child = this._children[i]; avatar._nativeCurCloneCount++; var destChild = child._cloneNative(localPositions, localRotations, localScales, animationNodeWorldMatrixs, animationNodeParentIndices, parentIndex, avatar); destNode.addChild(destChild); var transform = child.transform; var destTransform = destChild.transform; var destLocalPosition = destTransform.localPosition; var destLocalRotation = destTransform.localRotation; var destLocalScale = destTransform.localScale; transform.localPosition.cloneTo(destLocalPosition); transform.localRotation.cloneTo(destLocalRotation); transform.localScale.cloneTo(destLocalScale); destTransform.localPosition = destLocalPosition; destTransform.localRotation = destLocalRotation; destTransform.localScale = destLocalScale; } } } class Avatar extends Laya.Resource { constructor() { super(); this._nativeNodeCount = 0; this._nativeCurCloneCount = 0; } static _parse(data, propertyParams = null, constructParams = null) { var avatar = new Avatar(); avatar._rootNode = new AnimationNode(new Float32Array(3), new Float32Array(4), new Float32Array(3), new Float32Array(16)); if (Laya.Render.supportWebGLPlusAnimation) avatar._nativeNodeCount++; if (data.version) { var rootNode = data.rootNode; (rootNode) && (avatar._parseNode(rootNode, avatar._rootNode)); } return avatar; } static load(url, complete) { Laya.ILaya.loader.create(url, complete, null, Avatar.AVATAR); } _initCloneToAnimator(destNode, destAnimator) { destAnimator._avatarNodeMap[destNode.name] = destNode; for (var i = 0, n = destNode.getChildCount(); i < n; i++) this._initCloneToAnimator(destNode.getChildByIndex(i), destAnimator); } _parseNode(nodaData, node) { var name = nodaData.props.name; node.name = name; var props = nodaData.props; var transform = node.transform; var pos = transform.localPosition; var rot = transform.localRotation; var sca = transform.localScale; pos.fromArray(props.translate); rot.fromArray(props.rotation); sca.fromArray(props.scale); transform.localPosition = pos; transform.localRotation = rot; transform.localScale = sca; var childrenData = nodaData.child; for (var j = 0, n = childrenData.length; j < n; j++) { var childData = childrenData[j]; var childBone = new AnimationNode(new Float32Array(3), new Float32Array(4), new Float32Array(3), new Float32Array(16)); node.addChild(childBone); if (Laya.Render.supportWebGLPlusAnimation) this._nativeNodeCount++; this._parseNode(childData, childBone); } } _cloneDatasToAnimator(destAnimator) { var destRoot; destRoot = this._rootNode.clone(); var transform = this._rootNode.transform; var destTransform = destRoot.transform; var destPosition = destTransform.localPosition; var destRotation = destTransform.localRotation; var destScale = destTransform.localScale; transform.localPosition.cloneTo(destPosition); transform.localRotation.cloneTo(destRotation); transform.localScale.cloneTo(destScale); destTransform.localPosition = destPosition; destTransform.localRotation = destRotation; destTransform.localScale = destScale; destAnimator._avatarNodeMap = {}; this._initCloneToAnimator(destRoot, destAnimator); } cloneTo(destObject) { var destAvatar = destObject; var destRoot = this._rootNode.clone(); destAvatar._rootNode = destRoot; } clone() { var dest = new Avatar(); this.cloneTo(dest); return dest; } _cloneDatasToAnimatorNative(destAnimator) { var animationNodeLocalPositions = new Float32Array(this._nativeNodeCount * 3); var animationNodeLocalRotations = new Float32Array(this._nativeNodeCount * 4); var animationNodeLocalScales = new Float32Array(this._nativeNodeCount * 3); var animationNodeWorldMatrixs = new Float32Array(this._nativeNodeCount * 16); var animationNodeParentIndices = new Int16Array(this._nativeNodeCount); destAnimator._animationNodeLocalPositions = animationNodeLocalPositions; destAnimator._animationNodeLocalRotations = animationNodeLocalRotations; destAnimator._animationNodeLocalScales = animationNodeLocalScales; destAnimator._animationNodeWorldMatrixs = animationNodeWorldMatrixs; destAnimator._animationNodeParentIndices = animationNodeParentIndices; this._nativeCurCloneCount = 0; var destRoot = this._rootNode._cloneNative(animationNodeLocalPositions, animationNodeLocalRotations, animationNodeLocalScales, animationNodeWorldMatrixs, animationNodeParentIndices, -1, this); var transform = this._rootNode.transform; var destTransform = destRoot.transform; var destPosition = destTransform.localPosition; var destRotation = destTransform.localRotation; var destScale = destTransform.localScale; transform.localPosition.cloneTo(destPosition); transform.localRotation.cloneTo(destRotation); transform.localScale.cloneTo(destScale); destTransform.localPosition = destPosition; destTransform.localRotation = destRotation; destTransform.localScale = destScale; destAnimator._avatarNodeMap = {}; this._initCloneToAnimator(destRoot, destAnimator); } } Avatar.AVATAR = "AVATAR"; class Material extends Laya.Resource { constructor() { super(); this._shaderValues = null; this._shaderValues = new ShaderData(this); this.renderQueue = Material.RENDERQUEUE_OPAQUE; this._alphaTest = false; } static load(url, complete) { Laya.Laya.loader.create(url, complete, null, Material.MATERIAL); } static __initDefine__() { Material.SHADERDEFINE_ALPHATEST = Shader3D.getDefineByName("ALPHATEST"); } static _parse(data, propertyParams = null, constructParams = null) { var jsonData = data; var props = jsonData.props; var material; var classType = props.type; var clas = Laya.ClassUtils.getRegClass(classType); if (clas) material = new clas(); else throw ('_getSprite3DHierarchyInnerUrls 错误: ' + data.type + ' 不是类'); switch (jsonData.version) { case "LAYAMATERIAL:01": case "LAYAMATERIAL:02": var i, n; for (var key in props) { switch (key) { case "type": break; case "vectors": var vectors = props[key]; for (i = 0, n = vectors.length; i < n; i++) { var vector = vectors[i]; var vectorValue = vector.value; switch (vectorValue.length) { case 2: material[vector.name] = new Vector2(vectorValue[0], vectorValue[1]); break; case 3: material[vector.name] = new Vector3(vectorValue[0], vectorValue[1], vectorValue[2]); break; case 4: material[vector.name] = new Vector4(vectorValue[0], vectorValue[1], vectorValue[2], vectorValue[3]); break; default: throw new Error("BaseMaterial:unkonwn color length."); } } break; case "textures": var textures = props[key]; for (i = 0, n = textures.length; i < n; i++) { var texture = textures[i]; var path = texture.path; (path) && (material[texture.name] = Laya.Loader.getRes(path)); } break; case "defines": var defineNames = props[key]; for (i = 0, n = defineNames.length; i < n; i++) { var define = Shader3D.getDefineByName(defineNames[i]); material._shaderValues.addDefine(define); } break; case "renderStates": var renderStatesData = props[key]; var renderStateData = renderStatesData[0]; var mat = material; mat.blend = renderStateData.blend; mat.cull = renderStateData.cull; mat.depthTest = renderStateData.depthTest; mat.depthWrite = renderStateData.depthWrite; mat.blendSrc = renderStateData.srcBlend; mat.blendDst = renderStateData.dstBlend; break; case "cull": material.cull = props[key]; break; case "blend": material.blend = props[key]; break; case "depthWrite": material.depthWrite = props[key]; break; case "srcBlend": material.blendSrc = props[key]; break; case "dstBlend": material.blendDst = props[key]; break; default: material[key] = props[key]; } } break; default: throw new Error("BaseMaterial:unkonwn version."); } return material; } get shaderData() { return this._shaderValues; } get alphaTestValue() { return this._shaderValues.getNumber(Material.ALPHATESTVALUE); } set alphaTestValue(value) { this._shaderValues.setNumber(Material.ALPHATESTVALUE, value); } get alphaTest() { return this._alphaTest; } set alphaTest(value) { this._alphaTest = value; if (value) this._shaderValues.addDefine(Material.SHADERDEFINE_ALPHATEST); else this._shaderValues.removeDefine(Material.SHADERDEFINE_ALPHATEST); } _removeTetxureReference() { var data = this._shaderValues.getData(); for (var k in data) { var value = data[k]; if (value && value instanceof Laya.BaseTexture) value._removeReference(); } } _disposeResource() { if (this._referenceCount > 0) this._removeTetxureReference(); this._shaderValues = null; } _addReference(count = 1) { super._addReference(count); var data = this._shaderValues.getData(); for (var k in data) { var value = data[k]; if (value && value instanceof Laya.BaseTexture) value._addReference(); } } _removeReference(count = 1) { super._removeReference(count); this._removeTetxureReference(); } setShaderName(name) { this._shader = Shader3D.find(name); if (!this._shader) throw new Error("BaseMaterial: unknown shader name."); } cloneTo(destObject) { var destBaseMaterial = destObject; destBaseMaterial.name = this.name; destBaseMaterial.renderQueue = this.renderQueue; this._shaderValues.cloneTo(destBaseMaterial._shaderValues); } clone() { var dest = new Material(); this.cloneTo(dest); return dest; } get _defineDatas() { return this._shaderValues._defineDatas; } } Material.MATERIAL = "MATERIAL"; Material.RENDERQUEUE_OPAQUE = 2000; Material.RENDERQUEUE_ALPHATEST = 2450; Material.RENDERQUEUE_TRANSPARENT = 3000; Material.ALPHATESTVALUE = Shader3D.propertyNameToID("u_AlphaTestValue"); Material.SHADERDEFINE_ALPHATEST = null; class BaseMaterial { static load(url, complete) { Laya.Laya.loader.create(url, complete, null, Material.MATERIAL); } static __initDefine__() { BaseMaterial.SHADERDEFINE_ALPHATEST = Material.SHADERDEFINE_ALPHATEST; } } BaseMaterial.MATERIAL = "MATERIAL"; BaseMaterial.RENDERQUEUE_OPAQUE = 2000; BaseMaterial.RENDERQUEUE_ALPHATEST = 2450; BaseMaterial.RENDERQUEUE_TRANSPARENT = 3000; BaseMaterial.ALPHATESTVALUE = Shader3D.propertyNameToID("u_AlphaTestValue"); BaseMaterial.SHADERDEFINE_ALPHATEST = null; class RenderState { constructor() { this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_DISABLE; this.srcBlend = RenderState.BLENDPARAM_ONE; this.dstBlend = RenderState.BLENDPARAM_ZERO; this.srcBlendRGB = RenderState.BLENDPARAM_ONE; this.dstBlendRGB = RenderState.BLENDPARAM_ZERO; this.srcBlendAlpha = RenderState.BLENDPARAM_ONE; this.dstBlendAlpha = RenderState.BLENDPARAM_ZERO; this.blendConstColor = new Vector4(1, 1, 1, 1); this.blendEquation = RenderState.BLENDEQUATION_ADD; this.blendEquationRGB = RenderState.BLENDEQUATION_ADD; this.blendEquationAlpha = RenderState.BLENDEQUATION_ADD; this.depthTest = RenderState.DEPTHTEST_LEQUAL; this.depthWrite = true; } cloneTo(dest) { var destState = dest; destState.cull = this.cull; destState.blend = this.blend; destState.srcBlend = this.srcBlend; destState.dstBlend = this.dstBlend; destState.srcBlendRGB = this.srcBlendRGB; destState.dstBlendRGB = this.dstBlendRGB; destState.srcBlendAlpha = this.srcBlendAlpha; destState.dstBlendAlpha = this.dstBlendAlpha; this.blendConstColor.cloneTo(destState.blendConstColor); destState.blendEquation = this.blendEquation; destState.blendEquationRGB = this.blendEquationRGB; destState.blendEquationAlpha = this.blendEquationAlpha; destState.depthTest = this.depthTest; destState.depthWrite = this.depthWrite; } clone() { var dest = new RenderState(); this.cloneTo(dest); return dest; } } RenderState.CULL_NONE = 0; RenderState.CULL_FRONT = 1; RenderState.CULL_BACK = 2; RenderState.BLEND_DISABLE = 0; RenderState.BLEND_ENABLE_ALL = 1; RenderState.BLEND_ENABLE_SEPERATE = 2; RenderState.BLENDPARAM_ZERO = 0; RenderState.BLENDPARAM_ONE = 1; RenderState.BLENDPARAM_SRC_COLOR = 0x0300; RenderState.BLENDPARAM_ONE_MINUS_SRC_COLOR = 0x0301; RenderState.BLENDPARAM_DST_COLOR = 0x0306; RenderState.BLENDPARAM_ONE_MINUS_DST_COLOR = 0x0307; RenderState.BLENDPARAM_SRC_ALPHA = 0x0302; RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA = 0x0303; RenderState.BLENDPARAM_DST_ALPHA = 0x0304; RenderState.BLENDPARAM_ONE_MINUS_DST_ALPHA = 0x0305; RenderState.BLENDPARAM_SRC_ALPHA_SATURATE = 0x0308; RenderState.BLENDEQUATION_ADD = 0x8006; RenderState.BLENDEQUATION_SUBTRACT = 0x800A; RenderState.BLENDEQUATION_REVERSE_SUBTRACT = 0x800B; RenderState.DEPTHTEST_OFF = 0; RenderState.DEPTHTEST_NEVER = 0x0200; RenderState.DEPTHTEST_LESS = 0x0201; RenderState.DEPTHTEST_EQUAL = 0x0202; RenderState.DEPTHTEST_LEQUAL = 0x0203; RenderState.DEPTHTEST_GREATER = 0x0204; RenderState.DEPTHTEST_NOTEQUAL = 0x0205; RenderState.DEPTHTEST_GEQUAL = 0x0206; RenderState.DEPTHTEST_ALWAYS = 0x0207; class BlinnPhongMaterial extends Material { constructor() { super(); this._enableVertexColor = false; this.setShaderName("BLINNPHONG"); this._albedoIntensity = 1.0; this._albedoColor = new Vector4(1.0, 1.0, 1.0, 1.0); var sv = this._shaderValues; sv.setVector(BlinnPhongMaterial.ALBEDOCOLOR, new Vector4(1.0, 1.0, 1.0, 1.0)); sv.setVector(BlinnPhongMaterial.MATERIALSPECULAR, new Vector4(1.0, 1.0, 1.0, 1.0)); sv.setNumber(BlinnPhongMaterial.SHININESS, 0.078125); sv.setNumber(Material.ALPHATESTVALUE, 0.5); sv.setVector(BlinnPhongMaterial.TILINGOFFSET, new Vector4(1.0, 1.0, 0.0, 0.0)); this._enableLighting = true; this.renderMode = BlinnPhongMaterial.RENDERMODE_OPAQUE; } static __initDefine__() { BlinnPhongMaterial.SHADERDEFINE_DIFFUSEMAP = Shader3D.getDefineByName("DIFFUSEMAP"); BlinnPhongMaterial.SHADERDEFINE_NORMALMAP = Shader3D.getDefineByName("NORMALMAP"); BlinnPhongMaterial.SHADERDEFINE_SPECULARMAP = Shader3D.getDefineByName("SPECULARMAP"); BlinnPhongMaterial.SHADERDEFINE_TILINGOFFSET = Shader3D.getDefineByName("TILINGOFFSET"); BlinnPhongMaterial.SHADERDEFINE_ENABLEVERTEXCOLOR = Shader3D.getDefineByName("ENABLEVERTEXCOLOR"); } get _ColorR() { return this._albedoColor.x; } set _ColorR(value) { this._albedoColor.x = value; this.albedoColor = this._albedoColor; } get _ColorG() { return this._albedoColor.y; } set _ColorG(value) { this._albedoColor.y = value; this.albedoColor = this._albedoColor; } get _ColorB() { return this._albedoColor.z; } set _ColorB(value) { this._albedoColor.z = value; this.albedoColor = this._albedoColor; } get _ColorA() { return this._albedoColor.w; } set _ColorA(value) { this._albedoColor.w = value; this.albedoColor = this._albedoColor; } get _Color() { return this._shaderValues.getVector(BlinnPhongMaterial.ALBEDOCOLOR); } set _Color(value) { this.albedoColor = value; } get _SpecColorR() { return this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR).x; } set _SpecColorR(value) { this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR).x = value; } get _SpecColorG() { return this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR).y; } set _SpecColorG(value) { this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR).y = value; } get _SpecColorB() { return this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR).z; } set _SpecColorB(value) { this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR).z = value; } get _SpecColorA() { return this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR).w; } set _SpecColorA(value) { this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR).w = value; } get _SpecColor() { return this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR); } set _SpecColor(value) { this.specularColor = value; } get _AlbedoIntensity() { return this._albedoIntensity; } set _AlbedoIntensity(value) { if (this._albedoIntensity !== value) { var finalAlbedo = this._shaderValues.getVector(BlinnPhongMaterial.ALBEDOCOLOR); Vector4.scale(this._albedoColor, value, finalAlbedo); this._albedoIntensity = value; this._shaderValues.setVector(BlinnPhongMaterial.ALBEDOCOLOR, finalAlbedo); } } get _Shininess() { return this._shaderValues.getNumber(BlinnPhongMaterial.SHININESS); } set _Shininess(value) { value = Math.max(0.0, Math.min(1.0, value)); this._shaderValues.setNumber(BlinnPhongMaterial.SHININESS, value); } get _MainTex_STX() { return this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET).x; } set _MainTex_STX(x) { var tilOff = this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET); tilOff.x = x; this.tilingOffset = tilOff; } get _MainTex_STY() { return this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET).y; } set _MainTex_STY(y) { var tilOff = this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET); tilOff.y = y; this.tilingOffset = tilOff; } get _MainTex_STZ() { return this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET).z; } set _MainTex_STZ(z) { var tilOff = this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET); tilOff.z = z; this.tilingOffset = tilOff; } get _MainTex_STW() { return this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET).w; } set _MainTex_STW(w) { var tilOff = this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET); tilOff.w = w; this.tilingOffset = tilOff; } get _MainTex_ST() { return this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET); } set _MainTex_ST(value) { this.tilingOffset = value; } get _Cutoff() { return this.alphaTestValue; } set _Cutoff(value) { this.alphaTestValue = value; } set renderMode(value) { switch (value) { case BlinnPhongMaterial.RENDERMODE_OPAQUE: this.alphaTest = false; this.renderQueue = Material.RENDERQUEUE_OPAQUE; this.depthWrite = true; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_DISABLE; this.depthTest = RenderState.DEPTHTEST_LESS; break; case BlinnPhongMaterial.RENDERMODE_CUTOUT: this.renderQueue = Material.RENDERQUEUE_ALPHATEST; this.alphaTest = true; this.depthWrite = true; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_DISABLE; this.depthTest = RenderState.DEPTHTEST_LESS; break; case BlinnPhongMaterial.RENDERMODE_TRANSPARENT: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.alphaTest = false; this.depthWrite = false; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; this.depthTest = RenderState.DEPTHTEST_LESS; break; default: throw new Error("Material:renderMode value error."); } } get enableVertexColor() { return this._enableVertexColor; } set enableVertexColor(value) { this._enableVertexColor = value; if (value) this._shaderValues.addDefine(BlinnPhongMaterial.SHADERDEFINE_ENABLEVERTEXCOLOR); else this._shaderValues.removeDefine(BlinnPhongMaterial.SHADERDEFINE_ENABLEVERTEXCOLOR); } get tilingOffsetX() { return this._MainTex_STX; } set tilingOffsetX(x) { this._MainTex_STX = x; } get tilingOffsetY() { return this._MainTex_STY; } set tilingOffsetY(y) { this._MainTex_STY = y; } get tilingOffsetZ() { return this._MainTex_STZ; } set tilingOffsetZ(z) { this._MainTex_STZ = z; } get tilingOffsetW() { return this._MainTex_STW; } set tilingOffsetW(w) { this._MainTex_STW = w; } get tilingOffset() { return this._shaderValues.getVector(BlinnPhongMaterial.TILINGOFFSET); } set tilingOffset(value) { if (value) { if (value.x != 1 || value.y != 1 || value.z != 0 || value.w != 0) this._shaderValues.addDefine(BlinnPhongMaterial.SHADERDEFINE_TILINGOFFSET); else this._shaderValues.removeDefine(BlinnPhongMaterial.SHADERDEFINE_TILINGOFFSET); } else { this._shaderValues.removeDefine(BlinnPhongMaterial.SHADERDEFINE_TILINGOFFSET); } this._shaderValues.setVector(BlinnPhongMaterial.TILINGOFFSET, value); } get albedoColorR() { return this._ColorR; } set albedoColorR(value) { this._ColorR = value; } get albedoColorG() { return this._ColorG; } set albedoColorG(value) { this._ColorG = value; } get albedoColorB() { return this._ColorB; } set albedoColorB(value) { this._ColorB = value; } get albedoColorA() { return this._ColorA; } set albedoColorA(value) { this._ColorA = value; } get albedoColor() { return this._albedoColor; } set albedoColor(value) { var finalAlbedo = this._shaderValues.getVector(BlinnPhongMaterial.ALBEDOCOLOR); Vector4.scale(value, this._albedoIntensity, finalAlbedo); this._albedoColor = value; this._shaderValues.setVector(BlinnPhongMaterial.ALBEDOCOLOR, finalAlbedo); } get albedoIntensity() { return this._albedoIntensity; } set albedoIntensity(value) { this._AlbedoIntensity = value; } get specularColorR() { return this._SpecColorR; } set specularColorR(value) { this._SpecColorR = value; } get specularColorG() { return this._SpecColorG; } set specularColorG(value) { this._SpecColorG = value; } get specularColorB() { return this._SpecColorB; } set specularColorB(value) { this._SpecColorB = value; } get specularColorA() { return this._SpecColorA; } set specularColorA(value) { this._SpecColorA = value; } get specularColor() { return this._shaderValues.getVector(BlinnPhongMaterial.MATERIALSPECULAR); } set specularColor(value) { this._shaderValues.setVector(BlinnPhongMaterial.MATERIALSPECULAR, value); } get shininess() { return this._Shininess; } set shininess(value) { this._Shininess = value; } get albedoTexture() { return this._shaderValues.getTexture(BlinnPhongMaterial.ALBEDOTEXTURE); } set albedoTexture(value) { if (value) this._shaderValues.addDefine(BlinnPhongMaterial.SHADERDEFINE_DIFFUSEMAP); else this._shaderValues.removeDefine(BlinnPhongMaterial.SHADERDEFINE_DIFFUSEMAP); this._shaderValues.setTexture(BlinnPhongMaterial.ALBEDOTEXTURE, value); } get normalTexture() { return this._shaderValues.getTexture(BlinnPhongMaterial.NORMALTEXTURE); } set normalTexture(value) { if (value) this._shaderValues.addDefine(BlinnPhongMaterial.SHADERDEFINE_NORMALMAP); else this._shaderValues.removeDefine(BlinnPhongMaterial.SHADERDEFINE_NORMALMAP); this._shaderValues.setTexture(BlinnPhongMaterial.NORMALTEXTURE, value); } get specularTexture() { return this._shaderValues.getTexture(BlinnPhongMaterial.SPECULARTEXTURE); } set specularTexture(value) { if (value) this._shaderValues.addDefine(BlinnPhongMaterial.SHADERDEFINE_SPECULARMAP); else this._shaderValues.removeDefine(BlinnPhongMaterial.SHADERDEFINE_SPECULARMAP); this._shaderValues.setTexture(BlinnPhongMaterial.SPECULARTEXTURE, value); } get depthWrite() { return this._shaderValues.getBool(BlinnPhongMaterial.DEPTH_WRITE); } set depthWrite(value) { this._shaderValues.setBool(BlinnPhongMaterial.DEPTH_WRITE, value); } get cull() { return this._shaderValues.getInt(BlinnPhongMaterial.CULL); } set cull(value) { this._shaderValues.setInt(BlinnPhongMaterial.CULL, value); } get blend() { return this._shaderValues.getInt(BlinnPhongMaterial.BLEND); } set blend(value) { this._shaderValues.setInt(BlinnPhongMaterial.BLEND, value); } get blendSrc() { return this._shaderValues.getInt(BlinnPhongMaterial.BLEND_SRC); } set blendSrc(value) { this._shaderValues.setInt(BlinnPhongMaterial.BLEND_SRC, value); } get blendDst() { return this._shaderValues.getInt(BlinnPhongMaterial.BLEND_DST); } set blendDst(value) { this._shaderValues.setInt(BlinnPhongMaterial.BLEND_DST, value); } get depthTest() { return this._shaderValues.getInt(BlinnPhongMaterial.DEPTH_TEST); } set depthTest(value) { this._shaderValues.setInt(BlinnPhongMaterial.DEPTH_TEST, value); } clone() { var dest = new BlinnPhongMaterial(); this.cloneTo(dest); return dest; } cloneTo(destObject) { super.cloneTo(destObject); var destMaterial = destObject; destMaterial._enableLighting = this._enableLighting; destMaterial._albedoIntensity = this._albedoIntensity; destMaterial._enableVertexColor = this._enableVertexColor; this._albedoColor.cloneTo(destMaterial._albedoColor); } } BlinnPhongMaterial.RENDERMODE_OPAQUE = 0; BlinnPhongMaterial.RENDERMODE_CUTOUT = 1; BlinnPhongMaterial.RENDERMODE_TRANSPARENT = 2; BlinnPhongMaterial.ALBEDOTEXTURE = Shader3D.propertyNameToID("u_DiffuseTexture"); BlinnPhongMaterial.NORMALTEXTURE = Shader3D.propertyNameToID("u_NormalTexture"); BlinnPhongMaterial.SPECULARTEXTURE = Shader3D.propertyNameToID("u_SpecularTexture"); BlinnPhongMaterial.ALBEDOCOLOR = Shader3D.propertyNameToID("u_DiffuseColor"); BlinnPhongMaterial.MATERIALSPECULAR = Shader3D.propertyNameToID("u_MaterialSpecular"); BlinnPhongMaterial.SHININESS = Shader3D.propertyNameToID("u_Shininess"); BlinnPhongMaterial.TILINGOFFSET = Shader3D.propertyNameToID("u_TilingOffset"); BlinnPhongMaterial.CULL = Shader3D.propertyNameToID("s_Cull"); BlinnPhongMaterial.BLEND = Shader3D.propertyNameToID("s_Blend"); BlinnPhongMaterial.BLEND_SRC = Shader3D.propertyNameToID("s_BlendSrc"); BlinnPhongMaterial.BLEND_DST = Shader3D.propertyNameToID("s_BlendDst"); BlinnPhongMaterial.DEPTH_TEST = Shader3D.propertyNameToID("s_DepthTest"); BlinnPhongMaterial.DEPTH_WRITE = Shader3D.propertyNameToID("s_DepthWrite"); class EffectMaterial extends Material { constructor() { super(); this.setShaderName("Effect"); this._color = new Vector4(1.0, 1.0, 1.0, 1.0); this._shaderValues.setVector(EffectMaterial.TINTCOLOR, new Vector4(1.0, 1.0, 1.0, 1.0)); this.renderMode = EffectMaterial.RENDERMODE_ADDTIVE; } static __initDefine__() { EffectMaterial.SHADERDEFINE_MAINTEXTURE = Shader3D.getDefineByName("MAINTEXTURE"); EffectMaterial.SHADERDEFINE_TILINGOFFSET = Shader3D.getDefineByName("TILINGOFFSET"); EffectMaterial.SHADERDEFINE_ADDTIVEFOG = Shader3D.getDefineByName("ADDTIVEFOG"); } get _TintColorR() { return this._color.x; } set _TintColorR(value) { this._color.x = value; this.color = this._color; } get _TintColorG() { return this._color.y; } set _TintColorG(value) { this._color.y = value; this.color = this._color; } get _TintColorB() { return this._color.z; } set _TintColorB(value) { this._color.z = value; this.color = this._color; } get _TintColorA() { return this._color.w; } set _TintColorA(value) { this._color.w = value; this.color = this._color; } get _MainTex_STX() { return this._shaderValues.getVector(EffectMaterial.TILINGOFFSET).x; } set _MainTex_STX(x) { var tilOff = this._shaderValues.getVector(EffectMaterial.TILINGOFFSET); tilOff.x = x; this.tilingOffset = tilOff; } get _MainTex_STY() { return this._shaderValues.getVector(EffectMaterial.TILINGOFFSET).y; } set _MainTex_STY(y) { var tilOff = this._shaderValues.getVector(EffectMaterial.TILINGOFFSET); tilOff.y = y; this.tilingOffset = tilOff; } get _MainTex_STZ() { return this._shaderValues.getVector(EffectMaterial.TILINGOFFSET).z; } set _MainTex_STZ(z) { var tilOff = this._shaderValues.getVector(EffectMaterial.TILINGOFFSET); tilOff.z = z; this.tilingOffset = tilOff; } get _MainTex_STW() { return this._shaderValues.getVector(EffectMaterial.TILINGOFFSET).w; } set _MainTex_STW(w) { var tilOff = this._shaderValues.getVector(EffectMaterial.TILINGOFFSET); tilOff.w = w; this.tilingOffset = tilOff; } set renderMode(value) { switch (value) { case EffectMaterial.RENDERMODE_ADDTIVE: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.alphaTest = false; this.depthWrite = false; this.cull = RenderState.CULL_NONE; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE; this.depthTest = RenderState.DEPTHTEST_LESS; this._shaderValues.addDefine(EffectMaterial.SHADERDEFINE_ADDTIVEFOG); break; case EffectMaterial.RENDERMODE_ALPHABLENDED: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.alphaTest = false; this.depthWrite = false; this.cull = RenderState.CULL_NONE; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; this.depthTest = RenderState.DEPTHTEST_LESS; this._shaderValues.removeDefine(EffectMaterial.SHADERDEFINE_ADDTIVEFOG); break; default: throw new Error("MeshEffectMaterial : renderMode value error."); } } get colorR() { return this._TintColorR; } set colorR(value) { this._TintColorR = value; } get colorG() { return this._TintColorG; } set colorG(value) { this._TintColorG = value; } get colorB() { return this._TintColorB; } set colorB(value) { this._TintColorB = value; } get colorA() { return this._TintColorA; } set colorA(value) { this._TintColorA = value; } get color() { return this._shaderValues.getVector(EffectMaterial.TINTCOLOR); } set color(value) { this._shaderValues.setVector(EffectMaterial.TINTCOLOR, value); } get texture() { return this._shaderValues.getTexture(EffectMaterial.MAINTEXTURE); } set texture(value) { if (value) this._shaderValues.addDefine(EffectMaterial.SHADERDEFINE_MAINTEXTURE); else this._shaderValues.removeDefine(EffectMaterial.SHADERDEFINE_MAINTEXTURE); this._shaderValues.setTexture(EffectMaterial.MAINTEXTURE, value); } get tilingOffsetX() { return this._MainTex_STX; } set tilingOffsetX(x) { this._MainTex_STX = x; } get tilingOffsetY() { return this._MainTex_STY; } set tilingOffsetY(y) { this._MainTex_STY = y; } get tilingOffsetZ() { return this._MainTex_STZ; } set tilingOffsetZ(z) { this._MainTex_STZ = z; } get tilingOffsetW() { return this._MainTex_STW; } set tilingOffsetW(w) { this._MainTex_STW = w; } get tilingOffset() { return this._shaderValues.getVector(EffectMaterial.TILINGOFFSET); } set tilingOffset(value) { if (value) { if (value.x != 1 || value.y != 1 || value.z != 0 || value.w != 0) this._shaderValues.addDefine(EffectMaterial.SHADERDEFINE_TILINGOFFSET); else this._shaderValues.removeDefine(EffectMaterial.SHADERDEFINE_TILINGOFFSET); } else { this._shaderValues.removeDefine(EffectMaterial.SHADERDEFINE_TILINGOFFSET); } this._shaderValues.setVector(EffectMaterial.TILINGOFFSET, value); } get depthWrite() { return this._shaderValues.getBool(EffectMaterial.DEPTH_WRITE); } set depthWrite(value) { this._shaderValues.setBool(EffectMaterial.DEPTH_WRITE, value); } get cull() { return this._shaderValues.getInt(EffectMaterial.CULL); } set cull(value) { this._shaderValues.setInt(EffectMaterial.CULL, value); } get blend() { return this._shaderValues.getInt(EffectMaterial.BLEND); } set blend(value) { this._shaderValues.setInt(EffectMaterial.BLEND, value); } get blendSrc() { return this._shaderValues.getInt(EffectMaterial.BLEND_SRC); } set blendSrc(value) { this._shaderValues.setInt(EffectMaterial.BLEND_SRC, value); } get blendDst() { return this._shaderValues.getInt(EffectMaterial.BLEND_DST); } set blendDst(value) { this._shaderValues.setInt(EffectMaterial.BLEND_DST, value); } get depthTest() { return this._shaderValues.getInt(EffectMaterial.DEPTH_TEST); } set depthTest(value) { this._shaderValues.setInt(EffectMaterial.DEPTH_TEST, value); } clone() { var dest = new EffectMaterial(); this.cloneTo(dest); return dest; } } EffectMaterial.RENDERMODE_ADDTIVE = 0; EffectMaterial.RENDERMODE_ALPHABLENDED = 1; EffectMaterial.MAINTEXTURE = Shader3D.propertyNameToID("u_AlbedoTexture"); EffectMaterial.TINTCOLOR = Shader3D.propertyNameToID("u_AlbedoColor"); EffectMaterial.TILINGOFFSET = Shader3D.propertyNameToID("u_TilingOffset"); EffectMaterial.CULL = Shader3D.propertyNameToID("s_Cull"); EffectMaterial.BLEND = Shader3D.propertyNameToID("s_Blend"); EffectMaterial.BLEND_SRC = Shader3D.propertyNameToID("s_BlendSrc"); EffectMaterial.BLEND_DST = Shader3D.propertyNameToID("s_BlendDst"); EffectMaterial.DEPTH_TEST = Shader3D.propertyNameToID("s_DepthTest"); EffectMaterial.DEPTH_WRITE = Shader3D.propertyNameToID("s_DepthWrite"); class ExtendTerrainMaterial extends Material { constructor() { super(); this._enableLighting = true; this.setShaderName("ExtendTerrain"); this.renderMode = ExtendTerrainMaterial.RENDERMODE_OPAQUE; } static __initDefine__() { ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM1 = Shader3D.getDefineByName("ExtendTerrain_DETAIL_NUM1"); ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM2 = Shader3D.getDefineByName("ExtendTerrain_DETAIL_NUM2"); ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM3 = Shader3D.getDefineByName("ExtendTerrain_DETAIL_NUM3"); ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM4 = Shader3D.getDefineByName("ExtendTerrain_DETAIL_NUM4"); ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM5 = Shader3D.getDefineByName("ExtendTerrain_DETAIL_NUM5"); } get splatAlphaTexture() { return this._shaderValues.getTexture(ExtendTerrainMaterial.SPLATALPHATEXTURE); } set splatAlphaTexture(value) { this._shaderValues.setTexture(ExtendTerrainMaterial.SPLATALPHATEXTURE, value); } get diffuseTexture1() { return this._shaderValues.getTexture(ExtendTerrainMaterial.DIFFUSETEXTURE1); } set diffuseTexture1(value) { this._shaderValues.setTexture(ExtendTerrainMaterial.DIFFUSETEXTURE1, value); this._setDetailNum(1); } get diffuseTexture2() { return this._shaderValues.getTexture(ExtendTerrainMaterial.DIFFUSETEXTURE2); } set diffuseTexture2(value) { this._shaderValues.setTexture(ExtendTerrainMaterial.DIFFUSETEXTURE2, value); this._setDetailNum(2); } get diffuseTexture3() { return this._shaderValues.getTexture(ExtendTerrainMaterial.DIFFUSETEXTURE3); } set diffuseTexture3(value) { this._shaderValues.setTexture(ExtendTerrainMaterial.DIFFUSETEXTURE3, value); this._setDetailNum(3); } get diffuseTexture4() { return this._shaderValues.getTexture(ExtendTerrainMaterial.DIFFUSETEXTURE4); } set diffuseTexture4(value) { this._shaderValues.setTexture(ExtendTerrainMaterial.DIFFUSETEXTURE4, value); this._setDetailNum(4); } get diffuseTexture5() { return this._shaderValues.getTexture(ExtendTerrainMaterial.DIFFUSETEXTURE5); } set diffuseTexture5(value) { this._shaderValues.setTexture(ExtendTerrainMaterial.DIFFUSETEXTURE5, value); this._setDetailNum(5); } set diffuseScaleOffset1(scaleOffset1) { this._shaderValues.setVector(ExtendTerrainMaterial.DIFFUSESCALEOFFSET1, scaleOffset1); } set diffuseScaleOffset2(scaleOffset2) { this._shaderValues.setVector(ExtendTerrainMaterial.DIFFUSESCALEOFFSET2, scaleOffset2); } set diffuseScaleOffset3(scaleOffset3) { this._shaderValues.setVector(ExtendTerrainMaterial.DIFFUSESCALEOFFSET3, scaleOffset3); } set diffuseScaleOffset4(scaleOffset4) { this._shaderValues.setVector(ExtendTerrainMaterial.DIFFUSESCALEOFFSET4, scaleOffset4); } set diffuseScaleOffset5(scaleOffset5) { this._shaderValues.setVector(ExtendTerrainMaterial.DIFFUSESCALEOFFSET5, scaleOffset5); } set renderMode(value) { switch (value) { case ExtendTerrainMaterial.RENDERMODE_OPAQUE: this.renderQueue = Material.RENDERQUEUE_OPAQUE; this.depthWrite = true; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_DISABLE; this.depthTest = RenderState.DEPTHTEST_LESS; break; case ExtendTerrainMaterial.RENDERMODE_TRANSPARENT: this.renderQueue = Material.RENDERQUEUE_OPAQUE; this.depthWrite = false; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; this.depthTest = RenderState.DEPTHTEST_LEQUAL; break; default: throw new Error("ExtendTerrainMaterial:renderMode value error."); } } get depthWrite() { return this._shaderValues.getBool(ExtendTerrainMaterial.DEPTH_WRITE); } set depthWrite(value) { this._shaderValues.setBool(ExtendTerrainMaterial.DEPTH_WRITE, value); } get cull() { return this._shaderValues.getInt(ExtendTerrainMaterial.CULL); } set cull(value) { this._shaderValues.setInt(ExtendTerrainMaterial.CULL, value); } get blend() { return this._shaderValues.getInt(ExtendTerrainMaterial.BLEND); } set blend(value) { this._shaderValues.setInt(ExtendTerrainMaterial.BLEND, value); } get blendSrc() { return this._shaderValues.getInt(ExtendTerrainMaterial.BLEND_SRC); } set blendSrc(value) { this._shaderValues.setInt(ExtendTerrainMaterial.BLEND_SRC, value); } get blendDst() { return this._shaderValues.getInt(ExtendTerrainMaterial.BLEND_DST); } set blendDst(value) { this._shaderValues.setInt(ExtendTerrainMaterial.BLEND_DST, value); } get depthTest() { return this._shaderValues.getInt(ExtendTerrainMaterial.DEPTH_TEST); } set depthTest(value) { this._shaderValues.setInt(ExtendTerrainMaterial.DEPTH_TEST, value); } _setDetailNum(value) { switch (value) { case 1: this._shaderValues.addDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM1); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM2); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM3); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM4); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM5); break; case 2: this._shaderValues.addDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM2); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM1); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM3); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM4); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM5); break; case 3: this._shaderValues.addDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM3); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM1); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM2); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM4); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM5); break; case 4: this._shaderValues.addDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM4); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM1); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM2); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM3); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM5); break; case 5: this._shaderValues.addDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM5); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM1); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM2); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM3); this._shaderValues.removeDefine(ExtendTerrainMaterial.SHADERDEFINE_DETAIL_NUM4); break; } } clone() { var dest = new ExtendTerrainMaterial(); this.cloneTo(dest); return dest; } } ExtendTerrainMaterial.RENDERMODE_OPAQUE = 1; ExtendTerrainMaterial.RENDERMODE_TRANSPARENT = 2; ExtendTerrainMaterial.SPLATALPHATEXTURE = Shader3D.propertyNameToID("u_SplatAlphaTexture"); ExtendTerrainMaterial.DIFFUSETEXTURE1 = Shader3D.propertyNameToID("u_DiffuseTexture1"); ExtendTerrainMaterial.DIFFUSETEXTURE2 = Shader3D.propertyNameToID("u_DiffuseTexture2"); ExtendTerrainMaterial.DIFFUSETEXTURE3 = Shader3D.propertyNameToID("u_DiffuseTexture3"); ExtendTerrainMaterial.DIFFUSETEXTURE4 = Shader3D.propertyNameToID("u_DiffuseTexture4"); ExtendTerrainMaterial.DIFFUSETEXTURE5 = Shader3D.propertyNameToID("u_DiffuseTexture5"); ExtendTerrainMaterial.DIFFUSESCALEOFFSET1 = Shader3D.propertyNameToID("u_DiffuseScaleOffset1"); ExtendTerrainMaterial.DIFFUSESCALEOFFSET2 = Shader3D.propertyNameToID("u_DiffuseScaleOffset2"); ExtendTerrainMaterial.DIFFUSESCALEOFFSET3 = Shader3D.propertyNameToID("u_DiffuseScaleOffset3"); ExtendTerrainMaterial.DIFFUSESCALEOFFSET4 = Shader3D.propertyNameToID("u_DiffuseScaleOffset4"); ExtendTerrainMaterial.DIFFUSESCALEOFFSET5 = Shader3D.propertyNameToID("u_DiffuseScaleOffset5"); ExtendTerrainMaterial.CULL = Shader3D.propertyNameToID("s_Cull"); ExtendTerrainMaterial.BLEND = Shader3D.propertyNameToID("s_Blend"); ExtendTerrainMaterial.BLEND_SRC = Shader3D.propertyNameToID("s_BlendSrc"); ExtendTerrainMaterial.BLEND_DST = Shader3D.propertyNameToID("s_BlendDst"); ExtendTerrainMaterial.DEPTH_TEST = Shader3D.propertyNameToID("s_DepthTest"); ExtendTerrainMaterial.DEPTH_WRITE = Shader3D.propertyNameToID("s_DepthWrite"); (function (PBRRenderMode) { PBRRenderMode[PBRRenderMode["Opaque"] = 0] = "Opaque"; PBRRenderMode[PBRRenderMode["Cutout"] = 1] = "Cutout"; PBRRenderMode[PBRRenderMode["Fade"] = 2] = "Fade"; PBRRenderMode[PBRRenderMode["Transparent"] = 3] = "Transparent"; })(exports.PBRRenderMode || (exports.PBRRenderMode = {})); class PBRMaterial extends Material { constructor() { super(); this._enableEmission = false; this._shaderValues.setVector(PBRMaterial.ALBEDOCOLOR, new Vector4(1.0, 1.0, 1.0, 1.0)); this._shaderValues.setVector(PBRMaterial.EMISSIONCOLOR, new Vector4(1.0, 1.0, 1.0, 1.0)); this._shaderValues.setNumber(PBRMaterial.SMOOTHNESS, 0.5); this._shaderValues.setNumber(PBRMaterial.SMOOTHNESSSCALE, 1.0); this._shaderValues.setNumber(PBRMaterial.OCCLUSIONSTRENGTH, 1.0); this._shaderValues.setNumber(PBRMaterial.NORMALSCALE, 1.0); this._shaderValues.setNumber(PBRMaterial.PARALLAXSCALE, 0.001); this._shaderValues.setNumber(Material.ALPHATESTVALUE, 0.5); this.renderMode = exports.PBRRenderMode.Opaque; } static __init__() { PBRMaterial.SHADERDEFINE_ALBEDOTEXTURE = Shader3D.getDefineByName("ALBEDOTEXTURE"); PBRMaterial.SHADERDEFINE_NORMALTEXTURE = Shader3D.getDefineByName("NORMALTEXTURE"); PBRMaterial.SHADERDEFINE_PARALLAXTEXTURE = Shader3D.getDefineByName("PARALLAXTEXTURE"); PBRMaterial.SHADERDEFINE_OCCLUSIONTEXTURE = Shader3D.getDefineByName("OCCLUSIONTEXTURE"); PBRMaterial.SHADERDEFINE_EMISSION = Shader3D.getDefineByName("EMISSION"); PBRMaterial.SHADERDEFINE_EMISSIONTEXTURE = Shader3D.getDefineByName("EMISSIONTEXTURE"); PBRMaterial.SHADERDEFINE_TILINGOFFSET = Shader3D.getDefineByName("TILINGOFFSET"); PBRMaterial.SHADERDEFINE_TRANSPARENTBLEND = Shader3D.getDefineByName("TRANSPARENTBLEND"); PBRMaterial.SHADERDEFINE_LAYA_PBR_BRDF_HIGH = Shader3D.getDefineByName("LAYA_PBR_BRDF_HIGH"); PBRMaterial.SHADERDEFINE_LAYA_PBR_BRDF_LOW = Shader3D.getDefineByName("LAYA_PBR_BRDF_LOW"); } get albedoColor() { return this._shaderValues.getVector(PBRMaterial.ALBEDOCOLOR); } set albedoColor(value) { this._shaderValues.setVector(PBRMaterial.ALBEDOCOLOR, value); } get albedoTexture() { return this._shaderValues.getTexture(PBRMaterial.ALBEDOTEXTURE); } set albedoTexture(value) { if (value) this._shaderValues.addDefine(PBRMaterial.SHADERDEFINE_ALBEDOTEXTURE); else this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_ALBEDOTEXTURE); this._shaderValues.setTexture(PBRMaterial.ALBEDOTEXTURE, value); } get normalTexture() { return this._shaderValues.getTexture(PBRMaterial.NORMALTEXTURE); } set normalTexture(value) { if (value) { this._shaderValues.addDefine(PBRMaterial.SHADERDEFINE_NORMALTEXTURE); } else { this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_NORMALTEXTURE); } this._shaderValues.setTexture(PBRMaterial.NORMALTEXTURE, value); } get normalTextureScale() { return this._shaderValues.getNumber(PBRMaterial.NORMALSCALE); } set normalTextureScale(value) { this._shaderValues.setNumber(PBRMaterial.NORMALSCALE, value); } get parallaxTexture() { return this._shaderValues.getTexture(PBRMaterial.PARALLAXTEXTURE); } set parallaxTexture(value) { if (value) this._shaderValues.addDefine(PBRMaterial.SHADERDEFINE_PARALLAXTEXTURE); else this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_PARALLAXTEXTURE); this._shaderValues.setTexture(PBRMaterial.PARALLAXTEXTURE, value); } get parallaxTextureScale() { return this._shaderValues.getNumber(PBRMaterial.PARALLAXSCALE); } set parallaxTextureScale(value) { this._shaderValues.setNumber(PBRMaterial.PARALLAXSCALE, Math.max(0.005, Math.min(0.08, value))); } get occlusionTexture() { return this._shaderValues.getTexture(PBRMaterial.OCCLUSIONTEXTURE); } set occlusionTexture(value) { if (value) this._shaderValues.addDefine(PBRMaterial.SHADERDEFINE_OCCLUSIONTEXTURE); else this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_OCCLUSIONTEXTURE); this._shaderValues.setTexture(PBRMaterial.OCCLUSIONTEXTURE, value); } get occlusionTextureStrength() { return this._shaderValues.getNumber(PBRMaterial.OCCLUSIONSTRENGTH); } set occlusionTextureStrength(value) { this._shaderValues.setNumber(PBRMaterial.OCCLUSIONSTRENGTH, Math.max(0.0, Math.min(1.0, value))); } get smoothness() { return this._shaderValues.getNumber(PBRMaterial.SMOOTHNESS); } set smoothness(value) { this._shaderValues.setNumber(PBRMaterial.SMOOTHNESS, Math.max(0.0, Math.min(1.0, value))); } get smoothnessTextureScale() { return this._shaderValues.getNumber(PBRMaterial.SMOOTHNESSSCALE); } set smoothnessTextureScale(value) { this._shaderValues.setNumber(PBRMaterial.SMOOTHNESSSCALE, Math.max(0.0, Math.min(1.0, value))); } get enableEmission() { return this._enableEmission; } set enableEmission(value) { if (value) this._shaderValues.addDefine(PBRMaterial.SHADERDEFINE_EMISSION); else this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_EMISSION); this._enableEmission = value; } get emissionColor() { return this._shaderValues.getVector(PBRMaterial.EMISSIONCOLOR); } set emissionColor(value) { this._shaderValues.setVector(PBRMaterial.EMISSIONCOLOR, value); } get emissionTexture() { return this._shaderValues.getTexture(PBRMaterial.EMISSIONTEXTURE); } set emissionTexture(value) { if (value) this._shaderValues.addDefine(PBRMaterial.SHADERDEFINE_EMISSIONTEXTURE); else this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_EMISSIONTEXTURE); this._shaderValues.setTexture(PBRMaterial.EMISSIONTEXTURE, value); } get tilingOffset() { return this._shaderValues.getVector(PBRMaterial.TILINGOFFSET); } set tilingOffset(value) { if (value) { if (value.x != 1 || value.y != 1 || value.z != 0 || value.w != 0) this._shaderValues.addDefine(PBRMaterial.SHADERDEFINE_TILINGOFFSET); else this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_TILINGOFFSET); } else { this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_TILINGOFFSET); } this._shaderValues.setVector(PBRMaterial.TILINGOFFSET, value); } get depthWrite() { return this._shaderValues.getBool(PBRMaterial.DEPTH_WRITE); } set depthWrite(value) { this._shaderValues.setBool(PBRMaterial.DEPTH_WRITE, value); } get cull() { return this._shaderValues.getInt(PBRMaterial.CULL); } set cull(value) { this._shaderValues.setInt(PBRMaterial.CULL, value); } get blend() { return this._shaderValues.getInt(PBRMaterial.BLEND); } set blend(value) { this._shaderValues.setInt(PBRMaterial.BLEND, value); } get blendSrc() { return this._shaderValues.getInt(PBRMaterial.BLEND_SRC); } set blendSrc(value) { this._shaderValues.setInt(PBRMaterial.BLEND_SRC, value); } get blendDst() { return this._shaderValues.getInt(PBRMaterial.BLEND_DST); } set blendDst(value) { this._shaderValues.setInt(PBRMaterial.BLEND_DST, value); } get depthTest() { return this._shaderValues.getInt(PBRMaterial.DEPTH_TEST); } set depthTest(value) { this._shaderValues.setInt(PBRMaterial.DEPTH_TEST, value); } set renderMode(value) { switch (value) { case exports.PBRRenderMode.Opaque: this.alphaTest = false; this.renderQueue = Material.RENDERQUEUE_OPAQUE; this.depthWrite = true; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_DISABLE; this.depthTest = RenderState.DEPTHTEST_LESS; this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_TRANSPARENTBLEND); break; case exports.PBRRenderMode.Cutout: this.renderQueue = Material.RENDERQUEUE_ALPHATEST; this.alphaTest = true; this.depthWrite = true; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_DISABLE; this.depthTest = RenderState.DEPTHTEST_LESS; this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_TRANSPARENTBLEND); break; case exports.PBRRenderMode.Fade: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.alphaTest = false; this.depthWrite = false; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; this.depthTest = RenderState.DEPTHTEST_LESS; this._shaderValues.removeDefine(PBRMaterial.SHADERDEFINE_TRANSPARENTBLEND); break; case exports.PBRRenderMode.Transparent: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.alphaTest = false; this.depthWrite = false; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_ONE; this.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; this.depthTest = RenderState.DEPTHTEST_LESS; this._shaderValues.addDefine(PBRMaterial.SHADERDEFINE_TRANSPARENTBLEND); break; default: throw new Error("PBRMaterial:unknown renderMode value."); } } get enableReflection() { return true; } set enableReflection(value) { } } PBRMaterial.ALBEDOTEXTURE = Shader3D.propertyNameToID("u_AlbedoTexture"); PBRMaterial.ALBEDOCOLOR = Shader3D.propertyNameToID("u_AlbedoColor"); PBRMaterial.TILINGOFFSET = Shader3D.propertyNameToID("u_TilingOffset"); PBRMaterial.NORMALTEXTURE = Shader3D.propertyNameToID("u_NormalTexture"); PBRMaterial.NORMALSCALE = Shader3D.propertyNameToID("u_NormalScale"); PBRMaterial.SMOOTHNESS = Shader3D.propertyNameToID("u_Smoothness"); PBRMaterial.SMOOTHNESSSCALE = Shader3D.propertyNameToID("u_SmoothnessScale"); PBRMaterial.OCCLUSIONTEXTURE = Shader3D.propertyNameToID("u_OcclusionTexture"); PBRMaterial.OCCLUSIONSTRENGTH = Shader3D.propertyNameToID("u_occlusionStrength"); PBRMaterial.PARALLAXTEXTURE = Shader3D.propertyNameToID("u_ParallaxTexture"); PBRMaterial.PARALLAXSCALE = Shader3D.propertyNameToID("u_ParallaxScale"); PBRMaterial.EMISSIONTEXTURE = Shader3D.propertyNameToID("u_EmissionTexture"); PBRMaterial.EMISSIONCOLOR = Shader3D.propertyNameToID("u_EmissionColor"); PBRMaterial.CULL = Shader3D.propertyNameToID("s_Cull"); PBRMaterial.BLEND = Shader3D.propertyNameToID("s_Blend"); PBRMaterial.BLEND_SRC = Shader3D.propertyNameToID("s_BlendSrc"); PBRMaterial.BLEND_DST = Shader3D.propertyNameToID("s_BlendDst"); PBRMaterial.DEPTH_TEST = Shader3D.propertyNameToID("s_DepthTest"); PBRMaterial.DEPTH_WRITE = Shader3D.propertyNameToID("s_DepthWrite"); PBRMaterial.renderQuality = exports.PBRRenderQuality.High; var PBRPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n\tprecision highp int;\r\n#else\r\n\tprecision mediump float;\r\n\tprecision mediump int;\r\n#endif\r\n\r\n#define SETUP_BRDF_INPUT specularSetup\r\n\r\n#include \"Lighting.glsl\";\r\n#include \"PBRFSInput.glsl\";\r\n#include \"LayaPBRBRDF.glsl\";\r\n#include \"GlobalIllumination.glsl\";\r\n#include \"Shadow.glsl\"\r\n#include \"PBRCore.glsl\";\r\n\r\nvoid main()\r\n{\r\n\tfragmentForward();\r\n}"; var PBRVS = "#include \"PBRVSInput.glsl\";\r\n#include \"Lighting.glsl\";\r\n#include \"PBRVertex.glsl\";\r\n\r\nvoid main()\r\n{\r\n\tvertexForward();\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}"; var PBRShadowCasterPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n\tprecision highp int;\r\n#else\r\n\tprecision mediump float;\r\n\tprecision mediump int;\r\n#endif\r\n\r\n#include \"ShadowCasterFS.glsl\"\r\n\r\nvoid main()\r\n{\r\n\tgl_FragColor=shadowCasterFragment();\r\n}"; var PBRShadowCasterVS = "#include \"ShadowCasterVS.glsl\"\r\n\r\nvoid main()\r\n{\r\n\tvec4 positionCS = shadowCasterVertex();\r\n\tgl_Position=remapGLPositionZ(positionCS);\r\n}"; class ShaderVariable { constructor() { this.textureID = -1; } } class ShaderInstance extends Laya.Resource { constructor(vs, ps, attributeMap, uniformMap, shaderPass) { super(); this._stateParamsMap = []; this._uploadMark = -1; this._uploadRenderType = -1; this._vs = vs; this._ps = ps; this._attributeMap = attributeMap; this._uniformMap = uniformMap; this._shaderPass = shaderPass; this._create(); this.lock = true; } _create() { var gl = Laya.LayaGL.instance; this._program = gl.createProgram(); this._vshader = this._createShader(gl, this._vs, gl.VERTEX_SHADER); this._pshader = this._createShader(gl, this._ps, gl.FRAGMENT_SHADER); gl.attachShader(this._program, this._vshader); gl.attachShader(this._program, this._pshader); for (var k in this._attributeMap) gl.bindAttribLocation(this._program, this._attributeMap[k], k); gl.linkProgram(this._program); if (!Laya.Render.isConchApp && Shader3D.debugMode && !gl.getProgramParameter(this._program, gl.LINK_STATUS)) throw gl.getProgramInfoLog(this._program); var sceneParms = []; var cameraParms = []; var spriteParms = []; var materialParms = []; var customParms = []; this._customUniformParamsMap = []; var nUniformNum = gl.getProgramParameter(this._program, gl.ACTIVE_UNIFORMS); Laya.WebGLContext.useProgram(gl, this._program); this._curActTexIndex = 0; var one, i, n; for (i = 0; i < nUniformNum; i++) { var uniformData = gl.getActiveUniform(this._program, i); var uniName = uniformData.name; one = new ShaderVariable(); one.location = gl.getUniformLocation(this._program, uniName); if (uniName.indexOf('[0]') > 0) { one.name = uniName = uniName.substr(0, uniName.length - 3); one.isArray = true; } else { one.name = uniName; one.isArray = false; } one.type = uniformData.type; this._addShaderUnifiormFun(one); var uniformPeriod = this._uniformMap[uniName]; if (uniformPeriod != null) { one.dataOffset = Shader3D.propertyNameToID(uniName); switch (uniformPeriod) { case Shader3D.PERIOD_CUSTOM: customParms.push(one); break; case Shader3D.PERIOD_MATERIAL: materialParms.push(one); break; case Shader3D.PERIOD_SPRITE: spriteParms.push(one); break; case Shader3D.PERIOD_CAMERA: cameraParms.push(one); break; case Shader3D.PERIOD_SCENE: sceneParms.push(one); break; default: throw new Error("Shader3D: period is unkonw."); } } } this._sceneUniformParamsMap = Laya.LayaGL.instance.createCommandEncoder(sceneParms.length * 4 * 5 + 4, 64, true); for (i = 0, n = sceneParms.length; i < n; i++) this._sceneUniformParamsMap.addShaderUniform(sceneParms[i]); this._cameraUniformParamsMap = Laya.LayaGL.instance.createCommandEncoder(cameraParms.length * 4 * 5 + 4, 64, true); for (i = 0, n = cameraParms.length; i < n; i++) this._cameraUniformParamsMap.addShaderUniform(cameraParms[i]); this._spriteUniformParamsMap = Laya.LayaGL.instance.createCommandEncoder(spriteParms.length * 4 * 5 + 4, 64, true); for (i = 0, n = spriteParms.length; i < n; i++) this._spriteUniformParamsMap.addShaderUniform(spriteParms[i]); this._materialUniformParamsMap = Laya.LayaGL.instance.createCommandEncoder(materialParms.length * 4 * 5 + 4, 64, true); for (i = 0, n = materialParms.length; i < n; i++) this._materialUniformParamsMap.addShaderUniform(materialParms[i]); this._customUniformParamsMap.length = customParms.length; for (i = 0, n = customParms.length; i < n; i++) { var custom = customParms[i]; this._customUniformParamsMap[custom.dataOffset] = custom; } var stateMap = this._shaderPass._stateMap; for (var s in stateMap) this._stateParamsMap[stateMap[s]] = Shader3D.propertyNameToID(s); } _getRenderState(shaderDatas, stateIndex) { var stateID = this._stateParamsMap[stateIndex]; if (stateID == null) return null; else return shaderDatas[stateID]; } _disposeResource() { Laya.LayaGL.instance.deleteShader(this._vshader); Laya.LayaGL.instance.deleteShader(this._pshader); Laya.LayaGL.instance.deleteProgram(this._program); this._vshader = this._pshader = this._program = null; this._setGPUMemory(0); this._curActTexIndex = 0; } _addShaderUnifiormFun(one) { var gl = Laya.LayaGL.instance; one.caller = this; var isArray = one.isArray; switch (one.type) { case gl.BOOL: one.fun = this._uniform1i; one.uploadedValue = new Array(1); break; case gl.INT: one.fun = isArray ? this._uniform1iv : this._uniform1i; one.uploadedValue = new Array(1); break; case gl.FLOAT: one.fun = isArray ? this._uniform1fv : this._uniform1f; one.uploadedValue = new Array(1); break; case gl.FLOAT_VEC2: one.fun = isArray ? this._uniform_vec2v : this._uniform_vec2; one.uploadedValue = new Array(2); break; case gl.FLOAT_VEC3: one.fun = isArray ? this._uniform_vec3v : this._uniform_vec3; one.uploadedValue = new Array(3); break; case gl.FLOAT_VEC4: one.fun = isArray ? this._uniform_vec4v : this._uniform_vec4; one.uploadedValue = new Array(4); break; case gl.FLOAT_MAT2: one.fun = this._uniformMatrix2fv; break; case gl.FLOAT_MAT3: one.fun = this._uniformMatrix3fv; break; case gl.FLOAT_MAT4: one.fun = isArray ? this._uniformMatrix4fv : this._uniformMatrix4f; break; case gl.SAMPLER_2D: case gl.SAMPLER_2D_SHADOW: gl.uniform1i(one.location, this._curActTexIndex); one.textureID = Laya.WebGLContext._glTextureIDs[this._curActTexIndex++]; one.fun = this._uniform_sampler2D; break; case 0x8b5f: gl.uniform1i(one.location, this._curActTexIndex); one.textureID = Laya.WebGLContext._glTextureIDs[this._curActTexIndex++]; one.fun = this._uniform_sampler3D; break; case gl.SAMPLER_CUBE: gl.uniform1i(one.location, this._curActTexIndex); one.textureID = Laya.WebGLContext._glTextureIDs[this._curActTexIndex++]; one.fun = this._uniform_samplerCube; break; default: throw new Error("compile shader err!"); break; } } _createShader(gl, str, type) { var shader = gl.createShader(type); gl.shaderSource(shader, str); gl.compileShader(shader); if (Shader3D.debugMode && !gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw gl.getShaderInfoLog(shader); return shader; } _uniform1f(one, value) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== value) { Laya.LayaGL.instance.uniform1f(one.location, uploadedValue[0] = value); return 1; } return 0; } _uniform1fv(one, value) { if (value.length < 4) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== value[0] || uploadedValue[1] !== value[1] || uploadedValue[2] !== value[2] || uploadedValue[3] !== value[3]) { Laya.LayaGL.instance.uniform1fv(one.location, value); uploadedValue[0] = value[0]; uploadedValue[1] = value[1]; uploadedValue[2] = value[2]; uploadedValue[3] = value[3]; return 1; } return 0; } else { Laya.LayaGL.instance.uniform1fv(one.location, value); return 1; } } _uniform_vec2(one, v) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== v.x || uploadedValue[1] !== v.y) { Laya.LayaGL.instance.uniform2f(one.location, uploadedValue[0] = v.x, uploadedValue[1] = v.y); return 1; } return 0; } _uniform_vec2v(one, value) { if (value.length < 2) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== value[0] || uploadedValue[1] !== value[1] || uploadedValue[2] !== value[2] || uploadedValue[3] !== value[3]) { Laya.LayaGL.instance.uniform2fv(one.location, value); uploadedValue[0] = value[0]; uploadedValue[1] = value[1]; uploadedValue[2] = value[2]; uploadedValue[3] = value[3]; return 1; } return 0; } else { Laya.LayaGL.instance.uniform2fv(one.location, value); return 1; } } _uniform_vec3(one, v) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== v.x || uploadedValue[1] !== v.y || uploadedValue[2] !== v.z) { Laya.LayaGL.instance.uniform3f(one.location, uploadedValue[0] = v.x, uploadedValue[1] = v.y, uploadedValue[2] = v.z); return 1; } return 0; } _uniform_vec3v(one, v) { Laya.LayaGL.instance.uniform3fv(one.location, v); return 1; } _uniform_vec4(one, v) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== v.x || uploadedValue[1] !== v.y || uploadedValue[2] !== v.z || uploadedValue[3] !== v.w) { Laya.LayaGL.instance.uniform4f(one.location, uploadedValue[0] = v.x, uploadedValue[1] = v.y, uploadedValue[2] = v.z, uploadedValue[3] = v.w); return 1; } return 0; } _uniform_vec4v(one, v) { Laya.LayaGL.instance.uniform4fv(one.location, v); return 1; } _uniformMatrix2fv(one, value) { Laya.LayaGL.instance.uniformMatrix2fv(one.location, false, value); return 1; } _uniformMatrix3fv(one, value) { Laya.LayaGL.instance.uniformMatrix3fv(one.location, false, value); return 1; } _uniformMatrix4f(one, m) { var value = m.elements; Laya.LayaGL.instance.uniformMatrix4fv(one.location, false, value); return 1; } _uniformMatrix4fv(one, m) { Laya.LayaGL.instance.uniformMatrix4fv(one.location, false, m); return 1; } _uniform1i(one, value) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== value) { Laya.LayaGL.instance.uniform1i(one.location, uploadedValue[0] = value); return 1; } return 0; } _uniform1iv(one, value) { Laya.LayaGL.instance.uniform1iv(one.location, value); return 1; } _uniform_ivec2(one, value) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== value[0] || uploadedValue[1] !== value[1]) { Laya.LayaGL.instance.uniform2i(one.location, uploadedValue[0] = value[0], uploadedValue[1] = value[1]); return 1; } return 0; } _uniform_ivec2v(one, value) { Laya.LayaGL.instance.uniform2iv(one.location, value); return 1; } _uniform_vec3i(one, value) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== value[0] || uploadedValue[1] !== value[1] || uploadedValue[2] !== value[2]) { Laya.LayaGL.instance.uniform3i(one.location, uploadedValue[0] = value[0], uploadedValue[1] = value[1], uploadedValue[2] = value[2]); return 1; } return 0; } _uniform_vec3vi(one, value) { Laya.LayaGL.instance.uniform3iv(one.location, value); return 1; } _uniform_vec4i(one, value) { var uploadedValue = one.uploadedValue; if (uploadedValue[0] !== value[0] || uploadedValue[1] !== value[1] || uploadedValue[2] !== value[2] || uploadedValue[3] !== value[3]) { Laya.LayaGL.instance.uniform4i(one.location, uploadedValue[0] = value[0], uploadedValue[1] = value[1], uploadedValue[2] = value[2], uploadedValue[3] = value[3]); return 1; } return 0; } _uniform_vec4vi(one, value) { Laya.LayaGL.instance.uniform4iv(one.location, value); return 1; } _uniform_sampler2D(one, texture) { var value = texture._getSource() || texture.defaulteTexture._getSource(); var gl = Laya.LayaGL.instance; Laya.WebGLContext.activeTexture(gl, one.textureID); Laya.WebGLContext.bindTexture(gl, gl.TEXTURE_2D, value); return 0; } _uniform_sampler3D(one, texture) { var value = texture._getSource() || texture.defaulteTexture._getSource(); var gl = Laya.LayaGL.instance; Laya.WebGLContext.activeTexture(gl, one.textureID); Laya.WebGLContext.bindTexture(gl, WebGL2RenderingContext.TEXTURE_3D, value); return 0; } _uniform_samplerCube(one, texture) { var value = texture._getSource() || texture.defaulteTexture._getSource(); var gl = Laya.LayaGL.instance; Laya.WebGLContext.activeTexture(gl, one.textureID); Laya.WebGLContext.bindTexture(gl, gl.TEXTURE_CUBE_MAP, value); return 0; } bind() { return Laya.WebGLContext.useProgram(Laya.LayaGL.instance, this._program); } uploadUniforms(shaderUniform, shaderDatas, uploadUnTexture) { Laya.Stat.shaderCall += Laya.LayaGLRunner.uploadShaderUniforms(Laya.LayaGL.instance, shaderUniform, shaderDatas, uploadUnTexture); } uploadRenderStateBlendDepth(shaderDatas) { var gl = Laya.LayaGL.instance; var renderState = this._shaderPass.renderState; var datas = shaderDatas.getData(); var depthWrite = this._getRenderState(datas, Shader3D.RENDER_STATE_DEPTH_WRITE); var depthTest = this._getRenderState(datas, Shader3D.RENDER_STATE_DEPTH_TEST); var blend = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND); depthWrite == null && (depthWrite = renderState.depthWrite); depthTest == null && (depthTest = renderState.depthTest); blend == null && (blend = renderState.blend); Laya.WebGLContext.setDepthMask(gl, depthWrite); if (depthTest === RenderState.DEPTHTEST_OFF) Laya.WebGLContext.setDepthTest(gl, false); else { Laya.WebGLContext.setDepthTest(gl, true); Laya.WebGLContext.setDepthFunc(gl, depthTest); } switch (blend) { case RenderState.BLEND_DISABLE: Laya.WebGLContext.setBlend(gl, false); break; case RenderState.BLEND_ENABLE_ALL: var blendEquation = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_EQUATION); var srcBlend = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_SRC); var dstBlend = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_DST); blendEquation == null && (blendEquation = renderState.blendEquation); srcBlend == null && (srcBlend = renderState.srcBlend); dstBlend == null && (dstBlend = renderState.dstBlend); Laya.WebGLContext.setBlend(gl, true); Laya.WebGLContext.setBlendEquation(gl, blendEquation); Laya.WebGLContext.setBlendFunc(gl, srcBlend, dstBlend); break; case RenderState.BLEND_ENABLE_SEPERATE: var blendEquationRGB = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_EQUATION_RGB); var blendEquationAlpha = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_EQUATION_ALPHA); var srcRGB = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_SRC_RGB); var dstRGB = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_DST_RGB); var srcAlpha = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_SRC_ALPHA); var dstAlpha = this._getRenderState(datas, Shader3D.RENDER_STATE_BLEND_DST_ALPHA); blendEquationRGB == null && (blendEquationRGB = renderState.blendEquationRGB); blendEquationAlpha == null && (blendEquationAlpha = renderState.blendEquationAlpha); srcRGB == null && (srcRGB = renderState.srcBlendRGB); dstRGB == null && (dstRGB = renderState.dstBlendRGB); srcAlpha == null && (srcAlpha = renderState.srcBlendAlpha); dstAlpha == null && (dstAlpha = renderState.dstBlendAlpha); Laya.WebGLContext.setBlend(gl, true); Laya.WebGLContext.setBlendEquationSeparate(gl, blendEquationRGB, blendEquationAlpha); Laya.WebGLContext.setBlendFuncSeperate(gl, srcRGB, dstRGB, srcAlpha, dstAlpha); break; } } uploadRenderStateFrontFace(shaderDatas, isTarget, invertFront) { var gl = Laya.LayaGL.instance; var renderState = this._shaderPass.renderState; var datas = shaderDatas.getData(); var cull = this._getRenderState(datas, Shader3D.RENDER_STATE_CULL); cull == null && (cull = renderState.cull); var forntFace; switch (cull) { case RenderState.CULL_NONE: Laya.WebGLContext.setCullFace(gl, false); break; case RenderState.CULL_FRONT: Laya.WebGLContext.setCullFace(gl, true); if (isTarget) { if (invertFront) forntFace = gl.CCW; else forntFace = gl.CW; } else { if (invertFront) forntFace = gl.CW; else forntFace = gl.CCW; } Laya.WebGLContext.setFrontFace(gl, forntFace); break; case RenderState.CULL_BACK: Laya.WebGLContext.setCullFace(gl, true); if (isTarget) { if (invertFront) forntFace = gl.CW; else forntFace = gl.CCW; } else { if (invertFront) forntFace = gl.CCW; else forntFace = gl.CW; } Laya.WebGLContext.setFrontFace(gl, forntFace); break; } } uploadCustomUniform(index, data) { Laya.Stat.shaderCall += Laya.LayaGLRunner.uploadCustomUniform(Laya.LayaGL.instance, this._customUniformParamsMap, index, data); } _uniformMatrix2fvForNative(one, value) { Laya.LayaGL.instance.uniformMatrix2fvEx(one.location, false, value); return 1; } _uniformMatrix3fvForNative(one, value) { Laya.LayaGL.instance.uniformMatrix3fvEx(one.location, false, value); return 1; } _uniformMatrix4fvForNative(one, m) { Laya.LayaGL.instance.uniformMatrix4fvEx(one.location, false, m); return 1; } } class SimpleSingletonList extends SingletonList { constructor() { super(); } add(element) { var index = element._getIndexInList(); if (index !== -1) throw "SimpleSingletonList:" + element + " has in SingletonList."; this._add(element); element._setIndexInList(this.length++); } remove(element) { var index = element._getIndexInList(); this.length--; if (index !== this.length) { var end = this.elements[this.length]; this.elements[index] = end; end._setIndexInList(index); } element._setIndexInList(-1); } clear() { var elements = this.elements; for (var i = 0, n = this.length; i < n; i++) elements[i]._setIndexInList(-1); this.length = 0; } } class Color { constructor(r = 1, g = 1, b = 1, a = 1) { this.r = r; this.g = g; this.b = b; this.a = a; } static gammaToLinearSpace(value) { if (value <= 0.04045) return value / 12.92; else if (value < 1.0) return Math.pow((value + 0.055) / 1.055, 2.4); else return Math.pow(value, 2.4); } static linearToGammaSpace(value) { if (value <= 0.0) return 0.0; else if (value <= 0.0031308) return 12.92 * value; else if (value <= 1.0) return 1.055 * Math.pow(value, 0.41666) - 0.055; else return Math.pow(value, 0.41666); } toLinear(out) { out.r = Color.gammaToLinearSpace(this.r); out.g = Color.gammaToLinearSpace(this.g); out.b = Color.gammaToLinearSpace(this.b); } toGamma(out) { out.r = Color.linearToGammaSpace(this.r); out.g = Color.linearToGammaSpace(this.g); out.b = Color.linearToGammaSpace(this.b); } cloneTo(destObject) { var destColor = destObject; destColor.r = this.r; destColor.g = this.g; destColor.b = this.b; destColor.a = this.a; } clone() { var dest = new Color(); this.cloneTo(dest); return dest; } forNativeElement() { } } Color.RED = new Color(1, 0, 0, 1); Color.GREEN = new Color(0, 1, 0, 1); Color.BLUE = new Color(0, 0, 1, 1); Color.CYAN = new Color(0, 1, 1, 1); Color.YELLOW = new Color(1, 0.92, 0.016, 1); Color.MAGENTA = new Color(1, 0, 1, 1); Color.GRAY = new Color(0.5, 0.5, 0.5, 1); Color.WHITE = new Color(1, 1, 1, 1); Color.BLACK = new Color(0, 0, 0, 1); class CameraCullInfo { } class ShadowCullInfo { } class FrustumCulling { static __init__() { if (Laya.Render.supportWebGLPlusCulling) { FrustumCulling._cullingBufferLength = 0; FrustumCulling._cullingBuffer = new Float32Array(4096); } } static _drawTraversalCullingBound(renderList, debugTool) { var renders = renderList.elements; for (var i = 0, n = renderList.length; i < n; i++) { var color = FrustumCulling._tempColor0; color.r = 0; color.g = 1; color.b = 0; color.a = 1; Utils3D._drawBound(debugTool, renders[i].bounds._getBoundBox(), color); } } static _traversalCulling(cameraCullInfo, scene, context, renderList, customShader, replacementTag, isShadowCasterCull) { var renders = renderList.elements; var boundFrustum = cameraCullInfo.boundFrustum; var camPos = cameraCullInfo.position; var cullMask = cameraCullInfo.cullingMask; var loopCount = Laya.Stat.loopCount; for (var i = 0, n = renderList.length; i < n; i++) { var render = renders[i]; var canPass; if (isShadowCasterCull) canPass = render._castShadow && render._enable; else canPass = ((Math.pow(2, render._owner._layer) & cullMask) != 0) && render._enable; if (canPass) { Laya.Stat.frustumCulling++; if (!cameraCullInfo.useOcclusionCulling || render._needRender(boundFrustum, context)) { render._renderMark = loopCount; render._distanceForSort = Vector3.distance(render.bounds.getCenter(), camPos); var elements = render._renderElements; for (var j = 0, m = elements.length; j < m; j++) elements[j]._update(scene, context, customShader, replacementTag); } } } } static renderObjectCulling(cameraCullInfo, scene, context, customShader, replacementTag, isShadowCasterCull) { var opaqueQueue = scene._opaqueQueue; var transparentQueue = scene._transparentQueue; var renderList = scene._renders; scene._clearRenderQueue(); var octree = scene._octree; if (octree) { octree.updateMotionObjects(); octree.shrinkRootIfPossible(); octree.getCollidingWithFrustum(cameraCullInfo, context, customShader, replacementTag, isShadowCasterCull); } FrustumCulling._traversalCulling(cameraCullInfo, scene, context, renderList, customShader, replacementTag, isShadowCasterCull); if (FrustumCulling.debugFrustumCulling) { var debugTool = scene._debugTool; debugTool.clear(); if (octree) { octree.drawAllBounds(debugTool); octree.drawAllObjects(debugTool); } FrustumCulling._drawTraversalCullingBound(renderList, debugTool); } var count = opaqueQueue.elements.length; (count > 0) && (opaqueQueue._quickSort(0, count - 1)); count = transparentQueue.elements.length; (count > 0) && (transparentQueue._quickSort(0, count - 1)); } static cullingShadow(cullInfo, scene, context) { var renderList = scene._renders; scene._clearRenderQueue(); var opaqueQueue = scene._opaqueQueue; var position = cullInfo.position; var cullPlaneCount = cullInfo.cullPlaneCount; var cullPlanes = cullInfo.cullPlanes; var cullSphere = cullInfo.cullSphere; var direction = cullInfo.direction; var renders = renderList.elements; var loopCount = Laya.Stat.loopCount; for (var i = 0, n = renderList.length; i < n; i++) { var render = renders[i]; var canPass = render._castShadow && render._enable; if (canPass) { Laya.Stat.frustumCulling++; var bounds = render.bounds; var min = bounds.getMin(); var max = bounds.getMax(); var minX = min.x; var minY = min.y; var minZ = min.z; var maxX = max.x; var maxY = max.y; var maxZ = max.z; var pass = true; for (var j = 0; j < cullPlaneCount; j++) { var plane = cullPlanes[j]; var normal = plane.normal; if (plane.distance + (normal.x * (normal.x < 0.0 ? minX : maxX)) + (normal.y * (normal.y < 0.0 ? minY : maxY)) + (normal.z * (normal.z < 0.0 ? minZ : maxZ)) < 0.0) { pass = false; break; } } if (pass) { render._renderMark = loopCount; render._distanceForSort = Vector3.distance(bounds.getCenter(), position); var elements = render._renderElements; for (var j = 0, m = elements.length; j < m; j++) elements[j]._update(scene, context, null, null); } } } return opaqueQueue.elements.length > 0 ? true : false; } static cullingSpotShadow(cameraCullInfo, scene, context) { var renderList = scene._renders; scene._clearRenderQueue(); var opaqueQueue = scene._opaqueQueue; var renders = renderList.elements; var loopCount = Laya.Stat.loopCount; for (var i = 0, n = renderList.length; i < n; i++) { var render = renders[i]; var canPass = render._castShadow && render._enable; if (canPass) { if (render._needRender(cameraCullInfo.boundFrustum, context)) { var bounds = render.bounds; render._renderMark = loopCount; render._distanceForSort = Vector3.distance(bounds.getCenter(), cameraCullInfo.position); var elements = render._renderElements; for (var j = 0, m = elements.length; j < m; j++) elements[j]._update(scene, context, null, null); } } } return opaqueQueue.elements.length > 0 ? true : false; } static renderObjectCullingNative(camera, scene, context, renderList, customShader, replacementTag) { var i, j, m; var opaqueQueue = scene._opaqueQueue; var transparentQueue = scene._transparentQueue; scene._clearRenderQueue(); var validCount = renderList.length; var renders = renderList.elements; for (i = 0; i < validCount; i++) { renders[i].bounds; renders[i]._updateForNative && renders[i]._updateForNative(context); } var boundFrustum = camera.boundFrustum; FrustumCulling.cullingNative(camera._boundFrustumBuffer, FrustumCulling._cullingBuffer, scene._cullingBufferIndices, validCount, scene._cullingBufferResult); var loopCount = Laya.Stat.loopCount; var camPos = context.camera._transform.position; for (i = 0; i < validCount; i++) { var render = renders[i]; if (!camera.useOcclusionCulling || (camera._isLayerVisible(render._owner._layer) && render._enable && scene._cullingBufferResult[i])) { render._renderMark = loopCount; render._distanceForSort = Vector3.distance(render.bounds.getCenter(), camPos); var elements = render._renderElements; for (j = 0, m = elements.length; j < m; j++) { var element = elements[j]; element._update(scene, context, customShader, replacementTag); } } } var count = opaqueQueue.elements.length; (count > 0) && (opaqueQueue._quickSort(0, count - 1)); count = transparentQueue.elements.length; (count > 0) && (transparentQueue._quickSort(0, count - 1)); } static cullingNative(boundFrustumBuffer, cullingBuffer, cullingBufferIndices, cullingCount, cullingBufferResult) { return Laya.LayaGL.instance.culling(boundFrustumBuffer, cullingBuffer, cullingBufferIndices, cullingCount, cullingBufferResult); } } FrustumCulling._tempColor0 = new Color(); FrustumCulling._tempVector0 = new Vector3(); FrustumCulling._cameraCullInfo = new CameraCullInfo(); FrustumCulling._shadowCullInfo = new ShadowCullInfo(); FrustumCulling.debugFrustumCulling = false; class LightBound { } class ClusterData { constructor() { this.updateMark = -1; this.pointLightCount = 0; this.spotLightCount = 0; this.indices = []; } } class Cluster { constructor(xSlices, ySlices, zSlices, maxLightsPerClusterAverage) { this._updateMark = 0; this._depthSliceParam = new Vector2(); this._xSlices = xSlices; this._ySlices = ySlices; this._zSlices = zSlices; var clusterTexWidth = xSlices * ySlices; var clisterTexHeight = zSlices * (1 + Math.ceil(maxLightsPerClusterAverage / 4)); this._clusterTexture = Utils3D._createFloatTextureBuffer(clusterTexWidth, clisterTexHeight); this._clusterTexture.lock = true; this._clusterPixels = new Float32Array(clusterTexWidth * clisterTexHeight * 4); var clusterDatas = new Array(this._zSlices); for (var z = 0; z < this._zSlices; z++) { clusterDatas[z] = new Array(this._ySlices); for (var y = 0; y < this._ySlices; y++) { clusterDatas[z][y] = new Array(this._xSlices); for (var x = 0; x < this._xSlices; x++) clusterDatas[z][y][x] = new ClusterData(); } } this._clusterDatas = clusterDatas; } _insertSpotLightSphere(origin, forward, size, angle, testSphere) { var V = Cluster._tempVector35; V.x = testSphere.x - origin.x; V.y = testSphere.y - origin.y; V.z = testSphere.z - origin.z; var VlenSq = Vector3.dot(V, V); var sphereRadius = testSphere.w; var rangeCull = VlenSq > sphereRadius * sphereRadius; if (!rangeCull) return false; var V1len = Vector3.dot(V, forward); var distanceClosestPoint = Math.cos(angle) * Math.sqrt(VlenSq - V1len * V1len) - V1len * Math.sin(angle); var angleCull = distanceClosestPoint > sphereRadius; var frontCull = V1len > sphereRadius + size; var backCull = V1len < -sphereRadius; return !(angleCull || frontCull || backCull); } _placePointLightToClusters(lightIndex, lightBound) { var clusterDatas = this._clusterDatas; var updateMark = this._updateMark; for (var z = lightBound.zMin, zEnd = lightBound.zMax; z < zEnd; z++) { for (var y = lightBound.yMin, yEnd = lightBound.yMax; y < yEnd; y++) { for (var x = lightBound.xMin, xEnd = lightBound.xMax; x < xEnd; x++) { var data = clusterDatas[z][y][x]; if (data.updateMark != updateMark) { data.pointLightCount = 0; data.spotLightCount = 0; data.updateMark = updateMark; } var indices = data.indices; var lightCount = data.pointLightCount++; if (lightCount < indices.length) indices[lightCount] = lightIndex; else indices.push(lightIndex); } } } } _placeSpotLightToClusters(lightIndex, lightBound) { var clusterDatas = this._clusterDatas; var updateMark = this._updateMark; for (var z = lightBound.zMin, zEnd = lightBound.zMax; z < zEnd; z++) { for (var y = lightBound.yMin, yEnd = lightBound.yMax; y < yEnd; y++) { for (var x = lightBound.xMin, xEnd = lightBound.xMax; x < xEnd; x++) { var data = clusterDatas[z][y][x]; if (data.updateMark != updateMark) { data.pointLightCount = 0; data.spotLightCount = 0; data.updateMark = updateMark; } var indices = data.indices; var lightCount = data.pointLightCount + data.spotLightCount++; if (lightCount < indices.length) indices[lightCount] = lightIndex; else indices.push(lightIndex); } } } } _insertConePlane(origin, forward, radius, halfAngle, pNor) { var V1 = Cluster._tempVector36; var V2 = Cluster._tempVector37; Vector3.cross(pNor, forward, V1); Vector3.cross(V1, forward, V2); Vector3.normalize(V2, V2); var tanR = radius * Math.tan(halfAngle); var capRimX = origin.x + radius * forward.x + tanR * V2.x; var capRimY = origin.y + radius * forward.y + tanR * V2.y; var capRimZ = origin.z + radius * forward.z + tanR * V2.z; return capRimX * pNor.x + capRimY * pNor.y + capRimZ * pNor.z <= 0 || origin.x * pNor.x + origin.y * pNor.y + origin.z * pNor.z <= 0; } _shrinkSphereLightZPerspective(near, far, lightviewPos, radius, lightBound) { var lvZ = lightviewPos.z; var minZ = lvZ - radius; var maxZ = lvZ + radius; if ((minZ > far) || (maxZ <= near)) return false; var depthSliceParam = this._depthSliceParam; lightBound.zMin = Math.floor(Math.log2(Math.max(minZ, near)) * depthSliceParam.x - depthSliceParam.y); lightBound.zMax = Math.min(Math.ceil(Math.log2(maxZ) * depthSliceParam.x - depthSliceParam.y), this._zSlices); return true; } _shrinkSpotLightZPerspective(near, far, viewLightPos, viewConeCap, radius, halfAngle, lightBound) { var pbX = viewConeCap.x, pbY = viewConeCap.y, pbZ = viewConeCap.z; var rb = Math.tan(halfAngle) * radius; var paX = viewLightPos.x, paY = viewLightPos.y, paZ = viewLightPos.z; var aX = pbX - paX, aY = pbY - paY, aZ = pbZ - paZ; var dotA = aX * aX + aY * aY + aZ * aZ; var eZ = Math.sqrt(1.0 - aZ * aZ / dotA); var minZ = Math.max(Math.min(paZ, pbZ - eZ * rb), viewLightPos.z - radius); var maxZ = Math.min(Math.max(paZ, pbZ + eZ * rb), viewLightPos.z + radius); if ((minZ > far) || (maxZ <= near)) return false; var depthSliceParam = this._depthSliceParam; lightBound.zMin = Math.floor(Math.log2(Math.max(minZ, near)) * depthSliceParam.x - depthSliceParam.y); lightBound.zMax = Math.min(Math.ceil(Math.log2(maxZ) * depthSliceParam.x - depthSliceParam.y), this._zSlices); return true; } _shrinkSphereLightByBoundOrth(halfX, halfY, near, far, lightviewPos, radius, lightBound) { var lvZ = lightviewPos.z; var minZ = lvZ - radius, maxZ = lvZ + radius; if ((minZ > far) || (maxZ <= near)) return false; var lvX = lightviewPos.x; var minX = lvX - radius, maxX = lvX + radius; if ((minX > halfX) || (maxX <= -halfX)) return false; var lvY = lightviewPos.y; var minY = lvY - radius, maxY = lvY + radius; if ((minY > halfY) || (maxY <= -halfY)) return false; var xSlices = this._xSlices, ySlices = this._ySlices; var depthSliceParam = this._depthSliceParam; var xStride = halfX * 2 / xSlices, yStride = halfY * 2 / ySlices; lightBound.xMin = Math.max(Math.floor((minX + halfX) / xStride), 0); lightBound.xMax = Math.min(Math.ceil((maxX + halfX) / xStride), xSlices); lightBound.yMin = Math.max(Math.floor((halfY - maxY) / yStride), 0); lightBound.yMax = Math.min(Math.ceil((halfY - minY) / yStride), ySlices); lightBound.zMin = Math.floor(Math.log2(Math.max(minZ, near)) * depthSliceParam.x - depthSliceParam.y); lightBound.zMax = Math.min(Math.ceil(Math.log2(maxZ) * depthSliceParam.x - depthSliceParam.y), this._zSlices); return true; } _shrinkSpotLightByBoundOrth(halfX, halfY, near, far, viewLightPos, viewConeCap, radius, halfAngle, lightBound) { var pbX = viewConeCap.x, pbY = viewConeCap.y, pbZ = viewConeCap.z; var rb = Math.tan(halfAngle) * radius; var paX = viewLightPos.x, paY = viewLightPos.y, paZ = viewLightPos.z; var aX = pbX - paX, aY = pbY - paY, aZ = pbZ - paZ; var dotA = aX * aX + aY * aY + aZ * aZ; var eZ = Math.sqrt(1.0 - aZ * aZ / dotA); var minZ = Math.max(Math.min(paZ, pbZ - eZ * rb), viewLightPos.z - radius); var maxZ = Math.min(Math.max(paZ, pbZ + eZ * rb), viewLightPos.z + radius); if ((minZ > far) || (maxZ <= near)) return false; var eX = Math.sqrt(1.0 - aX * aX / dotA); var minX = Math.max(Math.min(paX, pbX - eX * rb), viewLightPos.x - radius); var maxX = Math.min(Math.max(paX, pbX + eX * rb), viewLightPos.x + radius); if ((minX > halfX) || (maxX <= -halfX)) return false; var eY = Math.sqrt(1.0 - aY * aY / dotA); var minY = Math.max(Math.min(paY, pbY - eY * rb), viewLightPos.y - radius); var maxY = Math.min(Math.max(paY, pbY + eY * rb), viewLightPos.y + radius); if ((minY > halfY) || (maxY <= -halfY)) return false; var xSlices = this._xSlices, ySlices = this._ySlices; var depthSliceParam = this._depthSliceParam; var xStride = halfX * 2 / xSlices, yStride = halfY * 2 / ySlices; lightBound.xMin = Math.max(Math.floor((minX + halfX) / xStride), 0); lightBound.xMax = Math.min(Math.ceil((maxX + halfX) / xStride), xSlices); lightBound.yMin = Math.max(Math.floor((halfY - maxY) / yStride), 0); lightBound.yMax = Math.min(Math.ceil((halfY - minY) / yStride), ySlices); lightBound.zMin = Math.floor(Math.log2(Math.max(minZ, near)) * depthSliceParam.x - depthSliceParam.y); lightBound.zMax = Math.min(Math.ceil(Math.log2(maxZ) * depthSliceParam.x - depthSliceParam.y), this._zSlices); return true; } _shrinkXYByRadiusPerspective(lightviewPos, radius, lightBound, xPlanes, yPlanes) { var xMin, yMin; var xMax, yMax; var lvX = lightviewPos.x, lvY = lightviewPos.y, lvZ = lightviewPos.z; var i; var n = this._ySlices + 1; for (i = 0; i < n; i++) { var plane = yPlanes[i]; if (lvY * plane.y + lvZ * plane.z < radius) { yMin = Math.max(0, i - 1); break; } } if (i == n) return false; yMax = this._ySlices; for (i = yMin + 1; i < n; i++) { var plane = yPlanes[i]; if (lvY * plane.y + lvZ * plane.z <= -radius) { yMax = Math.max(0, i); break; } } n = this._xSlices + 1; for (i = 0; i < n; i++) { var plane = xPlanes[i]; if (lvX * plane.x + lvZ * plane.z < radius) { xMin = Math.max(0, i - 1); break; } } xMax = this._xSlices; for (i = xMin + 1; i < n; i++) { var plane = xPlanes[i]; if (lvX * plane.x + lvZ * plane.z <= -radius) { xMax = Math.max(0, i); break; } } lightBound.xMin = xMin; lightBound.xMax = xMax; lightBound.yMin = yMin; lightBound.yMax = yMax; return true; } _shrinkSpotXYByConePerspective(lightviewPos, viewForward, radius, halfAngle, lightBound, xPlanes, yPlanes) { var xMin, yMin; var xMax, yMax; var normal = Cluster._tempVector32; var n = lightBound.yMax + 1; for (var i = lightBound.yMin + 1; i < n; i++) { if (this._insertConePlane(lightviewPos, viewForward, radius, halfAngle, yPlanes[i])) { yMin = Math.max(0, i - 1); break; } } yMax = lightBound.yMax; for (var i = yMin + 1; i < n; i++) { var plane = yPlanes[i]; normal.setValue(0, -plane.y, -plane.z); if (!this._insertConePlane(lightviewPos, viewForward, radius, halfAngle, normal)) { yMax = Math.max(0, i); break; } } n = lightBound.xMax + 1; for (var i = lightBound.xMin + 1; i < n; i++) { if (this._insertConePlane(lightviewPos, viewForward, radius, halfAngle, xPlanes[i])) { xMin = Math.max(0, i - 1); break; } } xMax = lightBound.xMax; for (var i = xMin + 1; i < n; i++) { var plane = xPlanes[i]; normal.setValue(-plane.x, 0, -plane.z); if (!this._insertConePlane(lightviewPos, viewForward, radius, halfAngle, normal)) { xMax = Math.max(0, i); break; } } lightBound.xMin = xMin; lightBound.xMax = xMax; lightBound.yMin = yMin; lightBound.yMax = yMax; } _updatePointLightPerspective(near, far, viewMat, pointLight, lightIndex, xPlanes, yPlanes) { var lightBound = Cluster._tempLightBound; var lightviewPos = Cluster._tempVector30; Vector3.transformV3ToV3(pointLight._transform.position, viewMat, lightviewPos); lightviewPos.z *= -1; if (!this._shrinkSphereLightZPerspective(near, far, lightviewPos, pointLight.range, lightBound)) return; if (!this._shrinkXYByRadiusPerspective(lightviewPos, pointLight.range, lightBound, xPlanes, yPlanes)) return; this._placePointLightToClusters(lightIndex, lightBound); } _updateSpotLightPerspective(near, far, viewMat, spotLight, lightIndex, xPlanes, yPlanes) { var lightBound = Cluster._tempLightBound; var viewPos = Cluster._tempVector30; var forward = Cluster._tempVector31; var viewConeCap = Cluster._tempVector34; var position = spotLight._transform.position; var range = spotLight.range; spotLight._transform.worldMatrix.getForward(forward); Vector3.normalize(forward, forward); Vector3.scale(forward, range, viewConeCap); Vector3.add(position, viewConeCap, viewConeCap); Vector3.transformV3ToV3(position, viewMat, viewPos); Vector3.transformV3ToV3(viewConeCap, viewMat, viewConeCap); viewPos.z *= -1; viewConeCap.z *= -1; var halfAngle = (spotLight.spotAngle / 2) * Math.PI / 180; if (!this._shrinkSpotLightZPerspective(near, far, viewPos, viewConeCap, range, halfAngle, lightBound)) return; if (!this._shrinkXYByRadiusPerspective(viewPos, range, lightBound, xPlanes, yPlanes)) return; var viewFor = Cluster._tempVector33; viewFor.x = viewConeCap.x - viewPos.x, viewFor.y = viewConeCap.y - viewPos.y, viewFor.z = viewConeCap.z - viewPos.z; Vector3.normalize(viewFor, viewFor); this._shrinkSpotXYByConePerspective(viewPos, viewFor, range, halfAngle, lightBound, xPlanes, yPlanes); this._placeSpotLightToClusters(lightIndex, lightBound); } _updatePointLightOrth(halfX, halfY, near, far, viewMat, pointLight, lightIndex) { var lightBound = Cluster._tempLightBound; var lightviewPos = Cluster._tempVector30; Vector3.transformV3ToV3(pointLight._transform.position, viewMat, lightviewPos); lightviewPos.z *= -1; if (!this._shrinkSphereLightByBoundOrth(halfX, halfY, near, far, lightviewPos, pointLight.range, lightBound)) return; this._placePointLightToClusters(lightIndex, lightBound); } _updateSpotLightOrth(halfX, halfY, near, far, viewMat, spotLight, lightIndex) { var lightBound = Cluster._tempLightBound; var viewPos = Cluster._tempVector30; var forward = Cluster._tempVector31; var viewConeCap = Cluster._tempVector34; var position = spotLight._transform.position; var range = spotLight.range; spotLight._transform.worldMatrix.getForward(forward); Vector3.normalize(forward, forward); Vector3.scale(forward, range, viewConeCap); Vector3.add(position, viewConeCap, viewConeCap); Vector3.transformV3ToV3(position, viewMat, viewPos); Vector3.transformV3ToV3(viewConeCap, viewMat, viewConeCap); viewPos.z *= -1; viewConeCap.z *= -1; var halfAngle = (spotLight.spotAngle / 2) * Math.PI / 180; if (!this._shrinkSpotLightByBoundOrth(halfX, halfY, near, far, viewPos, viewConeCap, range, halfAngle, lightBound)) return; this._placeSpotLightToClusters(lightIndex, lightBound); } update(camera, scene) { this._updateMark++; var camNear = camera.nearPlane; this._depthSliceParam.x = Config3D._config.lightClusterCount.z / Math.log2(camera.farPlane / camNear); this._depthSliceParam.y = Math.log2(camNear) * this._depthSliceParam.x; var near = camera.nearPlane; var far = camera.farPlane; var viewMat = camera.viewMatrix; var curCount = scene._directionLights._length; var pointLights = scene._pointLights; var poiCount = pointLights._length; var poiElements = pointLights._elements; var spotLights = scene._spotLights; var spoCount = spotLights._length; var spoElements = spotLights._elements; if (camera.orthographic) { var halfY = camera.orthographicVerticalSize / 2.0; var halfX = halfY * camera.aspectRatio; for (var i = 0; i < poiCount; i++, curCount++) this._updatePointLightOrth(halfX, halfY, near, far, viewMat, poiElements[i], curCount); for (var i = 0; i < spoCount; i++, curCount++) this._updateSpotLightOrth(halfX, halfY, near, far, viewMat, spoElements[i], curCount); } else { camera._updateClusterPlaneXY(); var xPlanes = camera._clusterXPlanes; var yPlanes = camera._clusterYPlanes; for (var i = 0; i < poiCount; i++, curCount++) this._updatePointLightPerspective(near, far, viewMat, poiElements[i], curCount, xPlanes, yPlanes); for (var i = 0; i < spoCount; i++, curCount++) this._updateSpotLightPerspective(near, far, viewMat, spoElements[i], curCount, xPlanes, yPlanes); } if (poiCount + spoCount > 0) { var xSlices = this._xSlices, ySlices = this._ySlices, zSlices = this._zSlices; var widthFloat = xSlices * ySlices * 4; var lightOff = widthFloat * zSlices; var clusterPixels = this._clusterPixels; var clusterPixelsCount = clusterPixels.length; var clusterDatas = this._clusterDatas; var updateMark = this._updateMark; var freeSpace = true; for (var z = 0; z < zSlices; z++) { for (var y = 0; y < ySlices; y++) { for (var x = 0; x < xSlices; x++) { var data = clusterDatas[z][y][x]; var clusterOff = (x + y * xSlices + z * xSlices * ySlices) * 4; if (data.updateMark !== updateMark) { clusterPixels[clusterOff] = 0; clusterPixels[clusterOff + 1] = 0; } else { if (freeSpace) { var indices = data.indices; var pCount = data.pointLightCount; var sCount = data.spotLightCount; var count = pCount + sCount; if (lightOff + count < clusterPixelsCount) { clusterPixels[clusterOff] = pCount; clusterPixels[clusterOff + 1] = sCount; clusterPixels[clusterOff + 2] = Math.floor(lightOff / widthFloat); clusterPixels[clusterOff + 3] = lightOff % widthFloat; for (var i = 0; i < count; i++) clusterPixels[lightOff++] = indices[i]; } else { count = clusterPixelsCount - (lightOff + count); pCount = Math.min(pCount, count); clusterPixels[clusterOff] = pCount; clusterPixels[clusterOff + 1] = Math.min(sCount, count - pCount); clusterPixels[clusterOff + 2] = Math.floor(lightOff / widthFloat); clusterPixels[clusterOff + 3] = lightOff % widthFloat; for (var i = 0; i < count; i++) clusterPixels[lightOff++] = indices[i]; freeSpace = false; } } } } } } var width = this._clusterTexture.width; this._clusterTexture.setSubPixels(0, 0, width, Math.ceil(lightOff / (4 * width)), clusterPixels); } } } Cluster._tempVector30 = new Vector3(); Cluster._tempVector31 = new Vector3(); Cluster._tempVector32 = new Vector3(); Cluster._tempVector33 = new Vector3(); Cluster._tempVector34 = new Vector3(); Cluster._tempVector35 = new Vector3(); Cluster._tempVector36 = new Vector3(); Cluster._tempVector37 = new Vector3(); Cluster._tempLightBound = new LightBound(); class SphericalHarmonicsL2 { constructor() { this._coefficients = new Float32Array(27); } getCoefficient(i, j) { return this._coefficients[i * 9 + j]; } setCoefficient(i, j, coefficient) { this._coefficients[i * 9 + j] = coefficient; } setCoefficients(i, coefficient0, coefficient1, coefficient2, coefficient3, coefficient4, coefficient5, coefficient6, coefficient7, coefficient8) { var offset = i * 9; this._coefficients[offset] = coefficient0; this._coefficients[++offset] = coefficient1; this._coefficients[++offset] = coefficient2; this._coefficients[++offset] = coefficient3; this._coefficients[++offset] = coefficient4; this._coefficients[++offset] = coefficient5; this._coefficients[++offset] = coefficient6; this._coefficients[++offset] = coefficient7; this._coefficients[++offset] = coefficient8; } cloneTo(dest) { if (this === dest) return; var coes = this._coefficients; var destCoes = dest._coefficients; for (var i = 0; i < 27; i++) destCoes[i] = coes[i]; } } SphericalHarmonicsL2._default = new SphericalHarmonicsL2(); class MouseTouch { constructor() { this._pressedSprite = null; this._pressedLoopCount = -1; this.sprite = null; this.mousePositionX = 0; this.mousePositionY = 0; } } class Touch { constructor() { this._indexInList = -1; this._identifier = -1; this._position = new Vector2(); } get identifier() { return this._identifier; } get position() { return this._position; } _getIndexInList() { return this._indexInList; } _setIndexInList(index) { this._indexInList = index; } } class Plane { constructor(normal, d = 0) { this.normal = normal; this.distance = d; } static createPlaneBy3P(point0, point1, point2, out) { var x1 = point1.x - point0.x; var y1 = point1.y - point0.y; var z1 = point1.z - point0.z; var x2 = point2.x - point0.x; var y2 = point2.y - point0.y; var z2 = point2.z - point0.z; var yz = (y1 * z2) - (z1 * y2); var xz = (z1 * x2) - (x1 * z2); var xy = (x1 * y2) - (y1 * x2); var invPyth = 1.0 / (Math.sqrt((yz * yz) + (xz * xz) + (xy * xy))); var x = yz * invPyth; var y = xz * invPyth; var z = xy * invPyth; var normal = out.normal; normal.x = x; normal.y = y; normal.z = z; out.distance = -((x * point0.x) + (y * point0.y) + (z * point0.z)); } normalize() { var normalEX = this.normal.x; var normalEY = this.normal.y; var normalEZ = this.normal.z; var magnitude = 1.0 / Math.sqrt(normalEX * normalEX + normalEY * normalEY + normalEZ * normalEZ); this.normal.x = normalEX * magnitude; this.normal.y = normalEY * magnitude; this.normal.z = normalEZ * magnitude; this.distance *= magnitude; } cloneTo(destObject) { var dest = destObject; this.normal.cloneTo(dest.normal); dest.distance = this.distance; } clone() { var dest = new Plane(new Vector3()); this.cloneTo(dest); return dest; } } Plane.PlaneIntersectionType_Back = 0; Plane.PlaneIntersectionType_Front = 1; Plane.PlaneIntersectionType_Intersecting = 2; class Ray { constructor(origin, direction) { this.origin = origin; this.direction = direction; } } class ContainmentType { } ContainmentType.Disjoint = 0; ContainmentType.Contains = 1; ContainmentType.Intersects = 2; class CollisionUtils { constructor() { } static distancePlaneToPoint(plane, point) { var dot = Vector3.dot(plane.normal, point); return dot - plane.distance; } static distanceBoxToPoint(box, point) { var boxMin = box.min; var boxMineX = boxMin.x; var boxMineY = boxMin.y; var boxMineZ = boxMin.z; var boxMax = box.max; var boxMaxeX = boxMax.x; var boxMaxeY = boxMax.y; var boxMaxeZ = boxMax.z; var pointeX = point.x; var pointeY = point.y; var pointeZ = point.z; var distance = 0; if (pointeX < boxMineX) distance += (boxMineX - pointeX) * (boxMineX - pointeX); if (pointeX > boxMaxeX) distance += (boxMaxeX - pointeX) * (boxMaxeX - pointeX); if (pointeY < boxMineY) distance += (boxMineY - pointeY) * (boxMineY - pointeY); if (pointeY > boxMaxeY) distance += (boxMaxeY - pointeY) * (boxMaxeY - pointeY); if (pointeZ < boxMineZ) distance += (boxMineZ - pointeZ) * (boxMineZ - pointeZ); if (pointeZ > boxMaxeZ) distance += (boxMaxeZ - pointeZ) * (boxMaxeZ - pointeZ); return Math.sqrt(distance); } static distanceBoxToBox(box1, box2) { var box1Mine = box1.min; var box1MineX = box1Mine.x; var box1MineY = box1Mine.y; var box1MineZ = box1Mine.z; var box1Maxe = box1.max; var box1MaxeX = box1Maxe.x; var box1MaxeY = box1Maxe.y; var box1MaxeZ = box1Maxe.z; var box2Mine = box2.min; var box2MineX = box2Mine.x; var box2MineY = box2Mine.y; var box2MineZ = box2Mine.z; var box2Maxe = box2.max; var box2MaxeX = box2Maxe.x; var box2MaxeY = box2Maxe.y; var box2MaxeZ = box2Maxe.z; var distance = 0; var delta; if (box1MineX > box2MaxeX) { delta = box1MineX - box2MaxeX; distance += delta * delta; } else if (box2MineX > box1MaxeX) { delta = box2MineX - box1MaxeX; distance += delta * delta; } if (box1MineY > box2MaxeY) { delta = box1MineY - box2MaxeY; distance += delta * delta; } else if (box2MineY > box1MaxeY) { delta = box2MineY - box1MaxeY; distance += delta * delta; } if (box1MineZ > box2MaxeZ) { delta = box1MineZ - box2MaxeZ; distance += delta * delta; } else if (box2MineZ > box1MaxeZ) { delta = box2MineZ - box1MaxeZ; distance += delta * delta; } return Math.sqrt(distance); } static distanceSphereToPoint(sphere, point) { var distance = Math.sqrt(Vector3.distanceSquared(sphere.center, point)); distance -= sphere.radius; return Math.max(distance, 0); } static distanceSphereToSphere(sphere1, sphere2) { var distance = Math.sqrt(Vector3.distanceSquared(sphere1.center, sphere2.center)); distance -= sphere1.radius + sphere2.radius; return Math.max(distance, 0); } static intersectsRayAndTriangleRD(ray, vertex1, vertex2, vertex3, out) { var rayO = ray.origin; var rayOeX = rayO.x; var rayOeY = rayO.y; var rayOeZ = rayO.z; var rayD = ray.direction; var rayDeX = rayD.x; var rayDeY = rayD.y; var rayDeZ = rayD.z; var v1eX = vertex1.x; var v1eY = vertex1.y; var v1eZ = vertex1.z; var v2eX = vertex2.x; var v2eY = vertex2.y; var v2eZ = vertex2.z; var v3eX = vertex3.x; var v3eY = vertex3.y; var v3eZ = vertex3.z; var _tempV30eX = CollisionUtils._tempV30.x; var _tempV30eY = CollisionUtils._tempV30.y; var _tempV30eZ = CollisionUtils._tempV30.z; _tempV30eX = v2eX - v1eX; _tempV30eY = v2eY - v1eY; _tempV30eZ = v2eZ - v1eZ; var _tempV31eX = CollisionUtils._tempV31.x; var _tempV31eY = CollisionUtils._tempV31.y; var _tempV31eZ = CollisionUtils._tempV31.z; _tempV31eX = v3eX - v1eX; _tempV31eY = v3eY - v1eY; _tempV31eZ = v3eZ - v1eZ; var _tempV32eX = CollisionUtils._tempV32.x; var _tempV32eY = CollisionUtils._tempV32.y; var _tempV32eZ = CollisionUtils._tempV32.z; _tempV32eX = (rayDeY * _tempV31eZ) - (rayDeZ * _tempV31eY); _tempV32eY = (rayDeZ * _tempV31eX) - (rayDeX * _tempV31eZ); _tempV32eZ = (rayDeX * _tempV31eY) - (rayDeY * _tempV31eX); var determinant = (_tempV30eX * _tempV32eX) + (_tempV30eY * _tempV32eY) + (_tempV30eZ * _tempV32eZ); if (MathUtils3D.isZero(determinant)) { return false; } var inversedeterminant = 1 / determinant; var _tempV33eX = CollisionUtils._tempV33.x; var _tempV33eY = CollisionUtils._tempV33.y; var _tempV33eZ = CollisionUtils._tempV33.z; _tempV33eX = rayOeX - v1eX; _tempV33eY = rayOeY - v1eY; _tempV33eZ = rayOeZ - v1eZ; var triangleU = (_tempV33eX * _tempV32eX) + (_tempV33eY * _tempV32eY) + (_tempV33eZ * _tempV32eZ); triangleU *= inversedeterminant; if (triangleU < 0 || triangleU > 1) { return false; } var _tempV34eX = CollisionUtils._tempV34.x; var _tempV34eY = CollisionUtils._tempV34.y; var _tempV34eZ = CollisionUtils._tempV34.z; _tempV34eX = (_tempV33eY * _tempV30eZ) - (_tempV33eZ * _tempV30eY); _tempV34eY = (_tempV33eZ * _tempV30eX) - (_tempV33eX * _tempV30eZ); _tempV34eZ = (_tempV33eX * _tempV30eY) - (_tempV33eY * _tempV30eX); var triangleV = ((rayDeX * _tempV34eX) + (rayDeY * _tempV34eY)) + (rayDeZ * _tempV34eZ); triangleV *= inversedeterminant; if (triangleV < 0 || triangleU + triangleV > 1) { return false; } var raydistance = (_tempV31eX * _tempV34eX) + (_tempV31eY * _tempV34eY) + (_tempV31eZ * _tempV34eZ); raydistance *= inversedeterminant; if (raydistance < 0) { return false; } return true; } static intersectsRayAndTriangleRP(ray, vertex1, vertex2, vertex3, out) { var distance; if (!CollisionUtils.intersectsRayAndTriangleRD(ray, vertex1, vertex2, vertex3, distance)) { out = Vector3._ZERO; return false; } Vector3.scale(ray.direction, distance, CollisionUtils._tempV30); Vector3.add(ray.origin, CollisionUtils._tempV30, out); return true; } static intersectsRayAndPoint(ray, point) { Vector3.subtract(ray.origin, point, CollisionUtils._tempV30); var b = Vector3.dot(CollisionUtils._tempV30, ray.direction); var c = Vector3.dot(CollisionUtils._tempV30, CollisionUtils._tempV30) - MathUtils3D.zeroTolerance; if (c > 0 && b > 0) return false; var discriminant = b * b - c; if (discriminant < 0) return false; return true; } static intersectsRayAndRay(ray1, ray2, out) { var ray1o = ray1.origin; var ray1oeX = ray1o.x; var ray1oeY = ray1o.y; var ray1oeZ = ray1o.z; var ray1d = ray1.direction; var ray1deX = ray1d.x; var ray1deY = ray1d.y; var ray1deZ = ray1d.z; var ray2o = ray2.origin; var ray2oeX = ray2o.x; var ray2oeY = ray2o.y; var ray2oeZ = ray2o.z; var ray2d = ray2.direction; var ray2deX = ray2d.x; var ray2deY = ray2d.y; var ray2deZ = ray2d.z; Vector3.cross(ray1d, ray2d, CollisionUtils._tempV30); var tempV3 = CollisionUtils._tempV30; var denominator = Vector3.scalarLength(CollisionUtils._tempV30); if (MathUtils3D.isZero(denominator)) { if (MathUtils3D.nearEqual(ray2oeX, ray1oeX) && MathUtils3D.nearEqual(ray2oeY, ray1oeY) && MathUtils3D.nearEqual(ray2oeZ, ray1oeZ)) { return true; } } denominator = denominator * denominator; var m11 = ray2oeX - ray1oeX; var m12 = ray2oeY - ray1oeY; var m13 = ray2oeZ - ray1oeZ; var m21 = ray2deX; var m22 = ray2deY; var m23 = ray2deZ; var m31 = tempV3.x; var m32 = tempV3.y; var m33 = tempV3.z; var dets = m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32 - m11 * m23 * m32 - m12 * m21 * m33 - m13 * m22 * m31; m21 = ray1deX; m22 = ray1deY; m23 = ray1deZ; var s = dets / denominator; Vector3.scale(ray1d, s, CollisionUtils._tempV30); Vector3.scale(ray2d, s, CollisionUtils._tempV31); Vector3.add(ray1o, CollisionUtils._tempV30, CollisionUtils._tempV32); Vector3.add(ray2o, CollisionUtils._tempV31, CollisionUtils._tempV33); var point1e = CollisionUtils._tempV32; var point2e = CollisionUtils._tempV33; if (!MathUtils3D.nearEqual(point2e.x, point1e.x) || !MathUtils3D.nearEqual(point2e.y, point1e.y) || !MathUtils3D.nearEqual(point2e.z, point1e.z)) { return false; } return true; } static intersectsPlaneAndTriangle(plane, vertex1, vertex2, vertex3) { var test1 = CollisionUtils.intersectsPlaneAndPoint(plane, vertex1); var test2 = CollisionUtils.intersectsPlaneAndPoint(plane, vertex2); var test3 = CollisionUtils.intersectsPlaneAndPoint(plane, vertex3); if (test1 == Plane.PlaneIntersectionType_Front && test2 == Plane.PlaneIntersectionType_Front && test3 == Plane.PlaneIntersectionType_Front) return Plane.PlaneIntersectionType_Front; if (test1 == Plane.PlaneIntersectionType_Back && test2 == Plane.PlaneIntersectionType_Back && test3 == Plane.PlaneIntersectionType_Back) return Plane.PlaneIntersectionType_Back; return Plane.PlaneIntersectionType_Intersecting; } static intersectsRayAndPlaneRD(ray, plane) { var planeNor = plane.normal; var direction = Vector3.dot(planeNor, ray.direction); if (Math.abs(direction) < MathUtils3D.zeroTolerance) return -1; var position = Vector3.dot(planeNor, ray.origin); var distance = (-plane.distance - position) / direction; if (distance < 0) { if (distance < -MathUtils3D.zeroTolerance) return -1; distance = 0; } return distance; } static intersectsRayAndPlaneRP(ray, plane, out) { var distance = CollisionUtils.intersectsRayAndPlaneRD(ray, plane); if (distance == -1) { out.setValue(0, 0, 0); return false; } var scaDis = CollisionUtils._tempV30; Vector3.scale(ray.direction, distance, scaDis); Vector3.add(ray.origin, scaDis, out); return true; } static intersectsRayAndBoxRD(ray, box) { var rayoe = ray.origin; var rayoeX = rayoe.x; var rayoeY = rayoe.y; var rayoeZ = rayoe.z; var rayde = ray.direction; var raydeX = rayde.x; var raydeY = rayde.y; var raydeZ = rayde.z; var boxMine = box.min; var boxMineX = boxMine.x; var boxMineY = boxMine.y; var boxMineZ = boxMine.z; var boxMaxe = box.max; var boxMaxeX = boxMaxe.x; var boxMaxeY = boxMaxe.y; var boxMaxeZ = boxMaxe.z; var out = 0; var tmax = MathUtils3D.MaxValue; if (MathUtils3D.isZero(raydeX)) { if (rayoeX < boxMineX || rayoeX > boxMaxeX) { return -1; } } else { var inverse = 1 / raydeX; var t1 = (boxMineX - rayoeX) * inverse; var t2 = (boxMaxeX - rayoeX) * inverse; if (t1 > t2) { var temp = t1; t1 = t2; t2 = temp; } out = Math.max(t1, out); tmax = Math.min(t2, tmax); if (out > tmax) { return -1; } } if (MathUtils3D.isZero(raydeY)) { if (rayoeY < boxMineY || rayoeY > boxMaxeY) { return -1; } } else { var inverse1 = 1 / raydeY; var t3 = (boxMineY - rayoeY) * inverse1; var t4 = (boxMaxeY - rayoeY) * inverse1; if (t3 > t4) { var temp1 = t3; t3 = t4; t4 = temp1; } out = Math.max(t3, out); tmax = Math.min(t4, tmax); if (out > tmax) { return -1; } } if (MathUtils3D.isZero(raydeZ)) { if (rayoeZ < boxMineZ || rayoeZ > boxMaxeZ) { return -1; } } else { var inverse2 = 1 / raydeZ; var t5 = (boxMineZ - rayoeZ) * inverse2; var t6 = (boxMaxeZ - rayoeZ) * inverse2; if (t5 > t6) { var temp2 = t5; t5 = t6; t6 = temp2; } out = Math.max(t5, out); tmax = Math.min(t6, tmax); if (out > tmax) { return -1; } } return out; } static intersectsRayAndBoxRP(ray, box, out) { var distance = CollisionUtils.intersectsRayAndBoxRD(ray, box); if (distance === -1) { Vector3._ZERO.cloneTo(out); return distance; } Vector3.scale(ray.direction, distance, CollisionUtils._tempV30); Vector3.add(ray.origin, CollisionUtils._tempV30, CollisionUtils._tempV31); CollisionUtils._tempV31.cloneTo(out); return distance; } static intersectsRayAndSphereRD(ray, sphere) { var sphereR = sphere.radius; Vector3.subtract(ray.origin, sphere.center, CollisionUtils._tempV30); var b = Vector3.dot(CollisionUtils._tempV30, ray.direction); var c = Vector3.dot(CollisionUtils._tempV30, CollisionUtils._tempV30) - (sphereR * sphereR); if (c > 0 && b > 0) { return -1; } var discriminant = b * b - c; if (discriminant < 0) { return -1; } var distance = -b - Math.sqrt(discriminant); if (distance < 0) distance = 0; return distance; } static intersectsRayAndSphereRP(ray, sphere, out) { var distance = CollisionUtils.intersectsRayAndSphereRD(ray, sphere); if (distance === -1) { Vector3._ZERO.cloneTo(out); return distance; } Vector3.scale(ray.direction, distance, CollisionUtils._tempV30); Vector3.add(ray.origin, CollisionUtils._tempV30, CollisionUtils._tempV31); CollisionUtils._tempV31.cloneTo(out); return distance; } static intersectsSphereAndTriangle(sphere, vertex1, vertex2, vertex3) { var sphereC = sphere.center; var sphereR = sphere.radius; CollisionUtils.closestPointPointTriangle(sphereC, vertex1, vertex2, vertex3, CollisionUtils._tempV30); Vector3.subtract(CollisionUtils._tempV30, sphereC, CollisionUtils._tempV31); var dot = Vector3.dot(CollisionUtils._tempV31, CollisionUtils._tempV31); return dot <= sphereR * sphereR; } static intersectsPlaneAndPoint(plane, point) { var distance = Vector3.dot(plane.normal, point) + plane.distance; if (distance > 0) return Plane.PlaneIntersectionType_Front; if (distance < 0) return Plane.PlaneIntersectionType_Back; return Plane.PlaneIntersectionType_Intersecting; } static intersectsPlaneAndPlane(plane1, plane2) { Vector3.cross(plane1.normal, plane2.normal, CollisionUtils._tempV30); var denominator = Vector3.dot(CollisionUtils._tempV30, CollisionUtils._tempV30); if (MathUtils3D.isZero(denominator)) return false; return true; } static intersectsPlaneAndPlaneRL(plane1, plane2, line) { var plane1nor = plane1.normal; var plane2nor = plane2.normal; Vector3.cross(plane1nor, plane2nor, CollisionUtils._tempV34); var denominator = Vector3.dot(CollisionUtils._tempV34, CollisionUtils._tempV34); if (MathUtils3D.isZero(denominator)) return false; Vector3.scale(plane2nor, plane1.distance, CollisionUtils._tempV30); Vector3.scale(plane1nor, plane2.distance, CollisionUtils._tempV31); Vector3.subtract(CollisionUtils._tempV30, CollisionUtils._tempV31, CollisionUtils._tempV32); Vector3.cross(CollisionUtils._tempV32, CollisionUtils._tempV34, CollisionUtils._tempV33); Vector3.normalize(CollisionUtils._tempV34, CollisionUtils._tempV34); return true; } static intersectsPlaneAndBox(plane, box) { var planeD = plane.distance; var planeNor = plane.normal; var planeNoreX = planeNor.x; var planeNoreY = planeNor.y; var planeNoreZ = planeNor.z; var boxMine = box.min; var boxMineX = boxMine.x; var boxMineY = boxMine.y; var boxMineZ = boxMine.z; var boxMaxe = box.max; var boxMaxeX = boxMaxe.x; var boxMaxeY = boxMaxe.y; var boxMaxeZ = boxMaxe.z; CollisionUtils._tempV30.x = (planeNoreX > 0) ? boxMineX : boxMaxeX; CollisionUtils._tempV30.y = (planeNoreY > 0) ? boxMineY : boxMaxeY; CollisionUtils._tempV30.z = (planeNoreZ > 0) ? boxMineZ : boxMaxeZ; CollisionUtils._tempV31.x = (planeNoreX > 0) ? boxMaxeX : boxMineX; CollisionUtils._tempV31.y = (planeNoreY > 0) ? boxMaxeY : boxMineY; CollisionUtils._tempV31.z = (planeNoreZ > 0) ? boxMaxeZ : boxMineZ; var distance = Vector3.dot(planeNor, CollisionUtils._tempV30); if (distance + planeD > 0) return Plane.PlaneIntersectionType_Front; distance = Vector3.dot(planeNor, CollisionUtils._tempV31); if (distance + planeD < 0) return Plane.PlaneIntersectionType_Back; return Plane.PlaneIntersectionType_Intersecting; } static intersectsPlaneAndSphere(plane, sphere) { var sphereR = sphere.radius; var distance = Vector3.dot(plane.normal, sphere.center) + plane.distance; if (distance > sphereR) return Plane.PlaneIntersectionType_Front; if (distance < -sphereR) return Plane.PlaneIntersectionType_Back; return Plane.PlaneIntersectionType_Intersecting; } static intersectsBoxAndBox(box1, box2) { var box1Mine = box1.min; var box1Maxe = box1.max; var box2Mine = box2.min; var box2Maxe = box2.max; if (box1Mine.x > box2Maxe.x || box2Mine.x > box1Maxe.x) return false; if (box1Mine.y > box2Maxe.y || box2Mine.y > box1Maxe.y) return false; if (box1Mine.z > box2Maxe.z || box2Mine.z > box1Maxe.z) return false; return true; } static intersectsBoxAndSphere(box, sphere) { var center = sphere.center; var radius = sphere.radius; var nearest = CollisionUtils._tempV30; Vector3.Clamp(center, box.min, box.max, nearest); var distance = Vector3.distanceSquared(center, nearest); return distance <= radius * radius; } static intersectsSphereAndSphere(sphere1, sphere2) { var radiisum = sphere1.radius + sphere2.radius; return Vector3.distanceSquared(sphere1.center, sphere2.center) <= radiisum * radiisum; } static boxContainsPoint(box, point) { var boxMine = box.min; var boxMaxe = box.max; if (boxMine.x <= point.x && boxMaxe.x >= point.x && boxMine.y <= point.y && boxMaxe.y >= point.y && boxMine.z <= point.z && boxMaxe.z >= point.z) return ContainmentType.Contains; return ContainmentType.Disjoint; } static boxContainsBox(box1, box2) { var box1Mine = box1.min; var box1MineX = box1Mine.x; var box1MineY = box1Mine.y; var box1MineZ = box1Mine.z; var box1Maxe = box1.max; var box1MaxeX = box1Maxe.x; var box1MaxeY = box1Maxe.y; var box1MaxeZ = box1Maxe.z; var box2Mine = box2.min; var box2MineX = box2Mine.x; var box2MineY = box2Mine.y; var box2MineZ = box2Mine.z; var box2Maxe = box2.max; var box2MaxeX = box2Maxe.x; var box2MaxeY = box2Maxe.y; var box2MaxeZ = box2Maxe.z; if (box1MaxeX < box2MineX || box1MineX > box2MaxeX) return ContainmentType.Disjoint; if (box1MaxeY < box2MineY || box1MineY > box2MaxeY) return ContainmentType.Disjoint; if (box1MaxeZ < box2MineZ || box1MineZ > box2MaxeZ) return ContainmentType.Disjoint; if (box1MineX <= box2MineX && box2MaxeX <= box1MaxeX && box1MineY <= box2MineY && box2MaxeY <= box1MaxeY && box1MineZ <= box2MineZ && box2MaxeZ <= box1MaxeZ) { return ContainmentType.Contains; } return ContainmentType.Intersects; } static boxContainsSphere(box, sphere) { var boxMin = box.min; var boxMineX = boxMin.x; var boxMineY = boxMin.y; var boxMineZ = boxMin.z; var boxMax = box.max; var boxMaxeX = boxMax.x; var boxMaxeY = boxMax.y; var boxMaxeZ = boxMax.z; var sphereC = sphere.center; var sphereCeX = sphereC.x; var sphereCeY = sphereC.y; var sphereCeZ = sphereC.z; var sphereR = sphere.radius; Vector3.Clamp(sphereC, boxMin, boxMax, CollisionUtils._tempV30); var distance = Vector3.distanceSquared(sphereC, CollisionUtils._tempV30); if (distance > sphereR * sphereR) return ContainmentType.Disjoint; if ((((boxMineX + sphereR <= sphereCeX) && (sphereCeX <= boxMaxeX - sphereR)) && ((boxMaxeX - boxMineX > sphereR) && (boxMineY + sphereR <= sphereCeY))) && (((sphereCeY <= boxMaxeY - sphereR) && (boxMaxeY - boxMineY > sphereR)) && (((boxMineZ + sphereR <= sphereCeZ) && (sphereCeZ <= boxMaxeZ - sphereR)) && (boxMaxeZ - boxMineZ > sphereR)))) return ContainmentType.Contains; return ContainmentType.Intersects; } static sphereContainsPoint(sphere, point) { if (Vector3.distanceSquared(point, sphere.center) <= sphere.radius * sphere.radius) return ContainmentType.Contains; return ContainmentType.Disjoint; } static sphereContainsTriangle(sphere, vertex1, vertex2, vertex3) { var test1 = CollisionUtils.sphereContainsPoint(sphere, vertex1); var test2 = CollisionUtils.sphereContainsPoint(sphere, vertex2); var test3 = CollisionUtils.sphereContainsPoint(sphere, vertex3); if (test1 == ContainmentType.Contains && test2 == ContainmentType.Contains && test3 == ContainmentType.Contains) return ContainmentType.Contains; if (CollisionUtils.intersectsSphereAndTriangle(sphere, vertex1, vertex2, vertex3)) return ContainmentType.Intersects; return ContainmentType.Disjoint; } static sphereContainsBox(sphere, box) { var sphereC = sphere.center; var sphereCeX = sphereC.x; var sphereCeY = sphereC.y; var sphereCeZ = sphereC.z; var sphereR = sphere.radius; var boxMin = box.min; var boxMineX = boxMin.x; var boxMineY = boxMin.y; var boxMineZ = boxMin.z; var boxMax = box.max; var boxMaxeX = boxMax.x; var boxMaxeY = boxMax.y; var boxMaxeZ = boxMax.z; var _tempV30e = CollisionUtils._tempV30; var _tempV30eX = _tempV30e.x; var _tempV30eY = _tempV30e.y; var _tempV30eZ = _tempV30e.z; if (!CollisionUtils.intersectsBoxAndSphere(box, sphere)) return ContainmentType.Disjoint; var radiusSquared = sphereR * sphereR; _tempV30eX = sphereCeX - boxMineX; _tempV30eY = sphereCeY - boxMaxeY; _tempV30eZ = sphereCeZ - boxMaxeZ; if (Vector3.scalarLengthSquared(CollisionUtils._tempV30) > radiusSquared) return ContainmentType.Intersects; _tempV30eX = sphereCeX - boxMaxeX; _tempV30eY = sphereCeY - boxMaxeY; _tempV30eZ = sphereCeZ - boxMaxeZ; if (Vector3.scalarLengthSquared(CollisionUtils._tempV30) > radiusSquared) return ContainmentType.Intersects; _tempV30eX = sphereCeX - boxMaxeX; _tempV30eY = sphereCeY - boxMineY; _tempV30eZ = sphereCeZ - boxMaxeZ; if (Vector3.scalarLengthSquared(CollisionUtils._tempV30) > radiusSquared) return ContainmentType.Intersects; _tempV30eX = sphereCeX - boxMineX; _tempV30eY = sphereCeY - boxMineY; _tempV30eZ = sphereCeZ - boxMaxeZ; if (Vector3.scalarLengthSquared(CollisionUtils._tempV30) > radiusSquared) return ContainmentType.Intersects; _tempV30eX = sphereCeX - boxMineX; _tempV30eY = sphereCeY - boxMaxeY; _tempV30eZ = sphereCeZ - boxMineZ; if (Vector3.scalarLengthSquared(CollisionUtils._tempV30) > radiusSquared) return ContainmentType.Intersects; _tempV30eX = sphereCeX - boxMaxeX; _tempV30eY = sphereCeY - boxMaxeY; _tempV30eZ = sphereCeZ - boxMineZ; if (Vector3.scalarLengthSquared(CollisionUtils._tempV30) > radiusSquared) return ContainmentType.Intersects; _tempV30eX = sphereCeX - boxMaxeX; _tempV30eY = sphereCeY - boxMineY; _tempV30eZ = sphereCeZ - boxMineZ; if (Vector3.scalarLengthSquared(CollisionUtils._tempV30) > radiusSquared) return ContainmentType.Intersects; _tempV30eX = sphereCeX - boxMineX; _tempV30eY = sphereCeY - boxMineY; _tempV30eZ = sphereCeZ - boxMineZ; if (Vector3.scalarLengthSquared(CollisionUtils._tempV30) > radiusSquared) return ContainmentType.Intersects; return ContainmentType.Contains; } static sphereContainsSphere(sphere1, sphere2) { var sphere1R = sphere1.radius; var sphere2R = sphere2.radius; var distance = Vector3.distance(sphere1.center, sphere2.center); if (sphere1R + sphere2R < distance) return ContainmentType.Disjoint; if (sphere1R - sphere2R < distance) return ContainmentType.Intersects; return ContainmentType.Contains; } static closestPointPointTriangle(point, vertex1, vertex2, vertex3, out) { Vector3.subtract(vertex2, vertex1, CollisionUtils._tempV30); Vector3.subtract(vertex3, vertex1, CollisionUtils._tempV31); Vector3.subtract(point, vertex1, CollisionUtils._tempV32); Vector3.subtract(point, vertex2, CollisionUtils._tempV33); Vector3.subtract(point, vertex3, CollisionUtils._tempV34); var d1 = Vector3.dot(CollisionUtils._tempV30, CollisionUtils._tempV32); var d2 = Vector3.dot(CollisionUtils._tempV31, CollisionUtils._tempV32); var d3 = Vector3.dot(CollisionUtils._tempV30, CollisionUtils._tempV33); var d4 = Vector3.dot(CollisionUtils._tempV31, CollisionUtils._tempV33); var d5 = Vector3.dot(CollisionUtils._tempV30, CollisionUtils._tempV34); var d6 = Vector3.dot(CollisionUtils._tempV31, CollisionUtils._tempV34); if (d1 <= 0 && d2 <= 0) { vertex1.cloneTo(out); return; } if (d3 >= 0 && d4 <= d3) { vertex2.cloneTo(out); return; } var vc = d1 * d4 - d3 * d2; if (vc <= 0 && d1 >= 0 && d3 <= 0) { var v = d1 / (d1 - d3); Vector3.scale(CollisionUtils._tempV30, v, out); Vector3.add(vertex1, out, out); return; } if (d6 >= 0 && d5 <= d6) { vertex3.cloneTo(out); return; } var vb = d5 * d2 - d1 * d6; if (vb <= 0 && d2 >= 0 && d6 <= 0) { var w = d2 / (d2 - d6); Vector3.scale(CollisionUtils._tempV31, w, out); Vector3.add(vertex1, out, out); return; } var va = d3 * d6 - d5 * d4; if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { var w3 = (d4 - d3) / ((d4 - d3) + (d5 - d6)); Vector3.subtract(vertex3, vertex2, out); Vector3.scale(out, w3, out); Vector3.add(vertex2, out, out); return; } var denom = 1 / (va + vb + vc); var v2 = vb * denom; var w2 = vc * denom; Vector3.scale(CollisionUtils._tempV30, v2, CollisionUtils._tempV35); Vector3.scale(CollisionUtils._tempV31, w2, CollisionUtils._tempV36); Vector3.add(CollisionUtils._tempV35, CollisionUtils._tempV36, out); Vector3.add(vertex1, out, out); } static closestPointPlanePoint(plane, point, out) { var planeN = plane.normal; var t = Vector3.dot(planeN, point) - plane.distance; Vector3.scale(planeN, t, CollisionUtils._tempV30); Vector3.subtract(point, CollisionUtils._tempV30, out); } static closestPointBoxPoint(box, point, out) { Vector3.max(point, box.min, CollisionUtils._tempV30); Vector3.min(CollisionUtils._tempV30, box.max, out); } static closestPointSpherePoint(sphere, point, out) { var sphereC = sphere.center; Vector3.subtract(point, sphereC, out); Vector3.normalize(out, out); Vector3.scale(out, sphere.radius, out); Vector3.add(out, sphereC, out); } static closestPointSphereSphere(sphere1, sphere2, out) { var sphere1C = sphere1.center; Vector3.subtract(sphere2.center, sphere1C, out); Vector3.normalize(out, out); Vector3.scale(out, sphere1.radius, out); Vector3.add(out, sphere1C, out); } } CollisionUtils._tempV30 = new Vector3(); CollisionUtils._tempV31 = new Vector3(); CollisionUtils._tempV32 = new Vector3(); CollisionUtils._tempV33 = new Vector3(); CollisionUtils._tempV34 = new Vector3(); CollisionUtils._tempV35 = new Vector3(); CollisionUtils._tempV36 = new Vector3(); (function (FrustumCorner) { FrustumCorner[FrustumCorner["FarBottomLeft"] = 0] = "FarBottomLeft"; FrustumCorner[FrustumCorner["FarTopLeft"] = 1] = "FarTopLeft"; FrustumCorner[FrustumCorner["FarTopRight"] = 2] = "FarTopRight"; FrustumCorner[FrustumCorner["FarBottomRight"] = 3] = "FarBottomRight"; FrustumCorner[FrustumCorner["nearBottomLeft"] = 4] = "nearBottomLeft"; FrustumCorner[FrustumCorner["nearTopLeft"] = 5] = "nearTopLeft"; FrustumCorner[FrustumCorner["nearTopRight"] = 6] = "nearTopRight"; FrustumCorner[FrustumCorner["nearBottomRight"] = 7] = "nearBottomRight"; FrustumCorner[FrustumCorner["unknown"] = 8] = "unknown"; })(exports.FrustumCorner || (exports.FrustumCorner = {})); class BoundFrustum { constructor(matrix) { this._matrix = matrix; this._near = new Plane(new Vector3()); this._far = new Plane(new Vector3()); this._left = new Plane(new Vector3()); this._right = new Plane(new Vector3()); this._top = new Plane(new Vector3()); this._bottom = new Plane(new Vector3()); BoundFrustum.getPlanesFromMatrix(this._matrix, this._near, this._far, this._left, this._right, this._top, this._bottom); } static getPlanesFromMatrix(m, np, fp, lp, rp, tp, bp) { var matrixE = m.elements; var m11 = matrixE[0]; var m12 = matrixE[1]; var m13 = matrixE[2]; var m14 = matrixE[3]; var m21 = matrixE[4]; var m22 = matrixE[5]; var m23 = matrixE[6]; var m24 = matrixE[7]; var m31 = matrixE[8]; var m32 = matrixE[9]; var m33 = matrixE[10]; var m34 = matrixE[11]; var m41 = matrixE[12]; var m42 = matrixE[13]; var m43 = matrixE[14]; var m44 = matrixE[15]; var nearNorE = np.normal; nearNorE.x = m13; nearNorE.y = m23; nearNorE.z = m33; np.distance = m43; np.normalize(); var farNorE = fp.normal; farNorE.x = m14 - m13; farNorE.y = m24 - m23; farNorE.z = m34 - m33; fp.distance = m44 - m43; fp.normalize(); var leftNorE = lp.normal; leftNorE.x = m14 + m11; leftNorE.y = m24 + m21; leftNorE.z = m34 + m31; lp.distance = m44 + m41; lp.normalize(); var rightNorE = rp.normal; rightNorE.x = m14 - m11; rightNorE.y = m24 - m21; rightNorE.z = m34 - m31; rp.distance = m44 - m41; rp.normalize(); var topNorE = tp.normal; topNorE.x = m14 - m12; topNorE.y = m24 - m22; topNorE.z = m34 - m32; tp.distance = m44 - m42; tp.normalize(); var bottomNorE = bp.normal; bottomNorE.x = m14 + m12; bottomNorE.y = m24 + m22; bottomNorE.z = m34 + m32; bp.distance = m44 + m42; bp.normalize(); } get matrix() { return this._matrix; } set matrix(matrix) { matrix.cloneTo(this._matrix); BoundFrustum.getPlanesFromMatrix(this._matrix, this._near, this._far, this._left, this._right, this._top, this._bottom); } get near() { return this._near; } get far() { return this._far; } get left() { return this._left; } get right() { return this._right; } get top() { return this._top; } get bottom() { return this._bottom; } equalsBoundFrustum(other) { return this._matrix.equalsOtherMatrix(other.matrix); } equalsObj(obj) { if (obj instanceof BoundFrustum) { var bf = obj; return this.equalsBoundFrustum(bf); } return false; } getPlane(index) { switch (index) { case 0: return this._near; case 1: return this._far; case 2: return this._left; case 3: return this._right; case 4: return this._top; case 5: return this._bottom; default: return null; } } static get3PlaneInterPoint(p1, p2, p3, out) { var p1Nor = p1.normal; var p2Nor = p2.normal; var p3Nor = p3.normal; Vector3.cross(p2Nor, p3Nor, BoundFrustum._tempV30); Vector3.cross(p3Nor, p1Nor, BoundFrustum._tempV31); Vector3.cross(p1Nor, p2Nor, BoundFrustum._tempV32); var a = Vector3.dot(p1Nor, BoundFrustum._tempV30); var b = Vector3.dot(p2Nor, BoundFrustum._tempV31); var c = Vector3.dot(p3Nor, BoundFrustum._tempV32); Vector3.scale(BoundFrustum._tempV30, -p1.distance / a, BoundFrustum._tempV33); Vector3.scale(BoundFrustum._tempV31, -p2.distance / b, BoundFrustum._tempV34); Vector3.scale(BoundFrustum._tempV32, -p3.distance / c, BoundFrustum._tempV35); Vector3.add(BoundFrustum._tempV33, BoundFrustum._tempV34, BoundFrustum._tempV36); Vector3.add(BoundFrustum._tempV35, BoundFrustum._tempV36, out); } getCorners(corners) { BoundFrustum.get3PlaneInterPoint(this._near, this._bottom, this._right, corners[exports.FrustumCorner.nearBottomRight]); BoundFrustum.get3PlaneInterPoint(this._near, this._top, this._right, corners[exports.FrustumCorner.nearTopRight]); BoundFrustum.get3PlaneInterPoint(this._near, this._top, this._left, corners[exports.FrustumCorner.nearTopLeft]); BoundFrustum.get3PlaneInterPoint(this._near, this._bottom, this._left, corners[exports.FrustumCorner.nearBottomLeft]); BoundFrustum.get3PlaneInterPoint(this._far, this._bottom, this._right, corners[exports.FrustumCorner.FarBottomRight]); BoundFrustum.get3PlaneInterPoint(this._far, this._top, this._right, corners[exports.FrustumCorner.FarTopRight]); BoundFrustum.get3PlaneInterPoint(this._far, this._top, this._left, corners[exports.FrustumCorner.FarTopLeft]); BoundFrustum.get3PlaneInterPoint(this._far, this._bottom, this._left, corners[exports.FrustumCorner.FarBottomLeft]); } containsPoint(point) { var result = Plane.PlaneIntersectionType_Front; var planeResult = Plane.PlaneIntersectionType_Front; for (var i = 0; i < 6; i++) { switch (i) { case 0: planeResult = CollisionUtils.intersectsPlaneAndPoint(this._near, point); break; case 1: planeResult = CollisionUtils.intersectsPlaneAndPoint(this._far, point); break; case 2: planeResult = CollisionUtils.intersectsPlaneAndPoint(this._left, point); break; case 3: planeResult = CollisionUtils.intersectsPlaneAndPoint(this._right, point); break; case 4: planeResult = CollisionUtils.intersectsPlaneAndPoint(this._top, point); break; case 5: planeResult = CollisionUtils.intersectsPlaneAndPoint(this._bottom, point); break; } switch (planeResult) { case Plane.PlaneIntersectionType_Back: return ContainmentType.Disjoint; case Plane.PlaneIntersectionType_Intersecting: result = Plane.PlaneIntersectionType_Intersecting; break; } } switch (result) { case Plane.PlaneIntersectionType_Intersecting: return ContainmentType.Intersects; default: return ContainmentType.Contains; } } intersects(box) { var min = box.min; var max = box.max; var minX = min.x; var minY = min.y; var minZ = min.z; var maxX = max.x; var maxY = max.y; var maxZ = max.z; var nearNormal = this._near.normal; if (this._near.distance + (nearNormal.x * (nearNormal.x < 0 ? minX : maxX)) + (nearNormal.y * (nearNormal.y < 0 ? minY : maxY)) + (nearNormal.z * (nearNormal.z < 0 ? minZ : maxZ)) < 0) return false; var leftNormal = this._left.normal; if (this._left.distance + (leftNormal.x * (leftNormal.x < 0 ? minX : maxX)) + (leftNormal.y * (leftNormal.y < 0 ? minY : maxY)) + (leftNormal.z * (leftNormal.z < 0 ? minZ : maxZ)) < 0) return false; var rightNormal = this._right.normal; if (this._right.distance + (rightNormal.x * (rightNormal.x < 0 ? minX : maxX)) + (rightNormal.y * (rightNormal.y < 0 ? minY : maxY)) + (rightNormal.z * (rightNormal.z < 0 ? minZ : maxZ)) < 0) return false; var bottomNormal = this._bottom.normal; if (this._bottom.distance + (bottomNormal.x * (bottomNormal.x < 0 ? minX : maxX)) + (bottomNormal.y * (bottomNormal.y < 0 ? minY : maxY)) + (bottomNormal.z * (bottomNormal.z < 0 ? minZ : maxZ)) < 0) return false; var topNormal = this._top.normal; if (this._top.distance + (topNormal.x * (topNormal.x < 0 ? minX : maxX)) + (topNormal.y * (topNormal.y < 0 ? minY : maxY)) + (topNormal.z * (topNormal.z < 0 ? minZ : maxZ)) < 0) return false; var farNormal = this._far.normal; if (this._far.distance + (farNormal.x * (farNormal.x < 0 ? minX : maxX)) + (farNormal.y * (farNormal.y < 0 ? minY : maxY)) + (farNormal.z * (farNormal.z < 0 ? minZ : maxZ)) < 0) return false; return true; } containsBoundBox(box) { var p = BoundFrustum._tempV30, n = BoundFrustum._tempV31; var boxMin = box.min; var boxMax = box.max; var result = ContainmentType.Contains; for (var i = 0; i < 6; i++) { var plane = this.getPlane(i); var planeNor = plane.normal; if (planeNor.x >= 0) { p.x = boxMax.x; n.x = boxMin.x; } else { p.x = boxMin.x; n.x = boxMax.x; } if (planeNor.y >= 0) { p.y = boxMax.y; n.y = boxMin.y; } else { p.y = boxMin.y; n.y = boxMax.y; } if (planeNor.z >= 0) { p.z = boxMax.z; n.z = boxMin.z; } else { p.z = boxMin.z; n.z = boxMax.z; } if (CollisionUtils.intersectsPlaneAndPoint(plane, p) === Plane.PlaneIntersectionType_Back) return ContainmentType.Disjoint; if (CollisionUtils.intersectsPlaneAndPoint(plane, n) === Plane.PlaneIntersectionType_Back) result = ContainmentType.Intersects; } return result; } containsBoundSphere(sphere) { var result = Plane.PlaneIntersectionType_Front; var planeResult = Plane.PlaneIntersectionType_Front; for (var i = 0; i < 6; i++) { switch (i) { case 0: planeResult = CollisionUtils.intersectsPlaneAndSphere(this._near, sphere); break; case 1: planeResult = CollisionUtils.intersectsPlaneAndSphere(this._far, sphere); break; case 2: planeResult = CollisionUtils.intersectsPlaneAndSphere(this._left, sphere); break; case 3: planeResult = CollisionUtils.intersectsPlaneAndSphere(this._right, sphere); break; case 4: planeResult = CollisionUtils.intersectsPlaneAndSphere(this._top, sphere); break; case 5: planeResult = CollisionUtils.intersectsPlaneAndSphere(this._bottom, sphere); break; } switch (planeResult) { case Plane.PlaneIntersectionType_Back: return ContainmentType.Disjoint; case Plane.PlaneIntersectionType_Intersecting: result = Plane.PlaneIntersectionType_Intersecting; break; } } switch (result) { case Plane.PlaneIntersectionType_Intersecting: return ContainmentType.Intersects; default: return ContainmentType.Contains; } } } BoundFrustum._tempV30 = new Vector3(); BoundFrustum._tempV31 = new Vector3(); BoundFrustum._tempV32 = new Vector3(); BoundFrustum._tempV33 = new Vector3(); BoundFrustum._tempV34 = new Vector3(); BoundFrustum._tempV35 = new Vector3(); BoundFrustum._tempV36 = new Vector3(); class Viewport { constructor(x, y, width, height) { this.minDepth = 0.0; this.maxDepth = 1.0; this.x = x; this.y = y; this.width = width; this.height = height; } project(source, matrix, out) { Vector3.transformV3ToV4(source, matrix, out); var x = out.x, y = out.y, z = out.z; var w = out.w; if (w !== 1.0) { x = x / w; y = y / w; z = z / w; } out.x = (x + 1.0) * 0.5 * this.width + this.x; out.y = (-y + 1.0) * 0.5 * this.height + this.y; out.z = z * (this.maxDepth - this.minDepth) + this.minDepth; } unprojectFromMat(source, matrix, out) { var matrixEleme = matrix.elements; out.x = (((source.x - this.x) / this.width) * 2.0) - 1.0; out.y = -((((source.y - this.y) / this.height) * 2.0) - 1.0); out.z = (source.z - this.minDepth) / (this.maxDepth - this.minDepth); var a = (((out.x * matrixEleme[3]) + (out.y * matrixEleme[7])) + (out.z * matrixEleme[11])) + matrixEleme[15]; Vector3.transformV3ToV3(out, matrix, out); if (a !== 1.0) { out.x = out.x / a; out.y = out.y / a; out.z = out.z / a; } } unprojectFromWVP(source, projection, view, world, out) { Matrix4x4.multiply(projection, view, Viewport._tempMatrix4x4); (world) && (Matrix4x4.multiply(Viewport._tempMatrix4x4, world, Viewport._tempMatrix4x4)); Viewport._tempMatrix4x4.invert(Viewport._tempMatrix4x4); this.unprojectFromMat(source, Viewport._tempMatrix4x4, out); } cloneTo(out) { out.x = this.x; out.y = this.y; out.width = this.width; out.height = this.height; out.minDepth = this.minDepth; out.maxDepth = this.maxDepth; } } Viewport._tempMatrix4x4 = new Matrix4x4(); class Picker { constructor() { } static calculateCursorRay(point, viewPort, projectionMatrix, viewMatrix, world, out) { var x = point.x; var y = point.y; var nearSource = Picker._tempVector30; var nerSourceE = nearSource; nerSourceE.x = x; nerSourceE.y = y; nerSourceE.z = viewPort.minDepth; var farSource = Picker._tempVector31; var farSourceE = farSource; farSourceE.x = x; farSourceE.y = y; farSourceE.z = viewPort.maxDepth; var nearPoint = out.origin; var farPoint = Picker._tempVector32; viewPort.unprojectFromWVP(nearSource, projectionMatrix, viewMatrix, world, nearPoint); viewPort.unprojectFromWVP(farSource, projectionMatrix, viewMatrix, world, farPoint); var outDire = out.direction; outDire.x = farPoint.x - nearPoint.x; outDire.y = farPoint.y - nearPoint.y; outDire.z = farPoint.z - nearPoint.z; Vector3.normalize(out.direction, out.direction); } static rayIntersectsTriangle(ray, vertex1, vertex2, vertex3) { var result; var edge1 = Picker._tempVector30, edge2 = Picker._tempVector31; Vector3.subtract(vertex2, vertex1, edge1); Vector3.subtract(vertex3, vertex1, edge2); var directionCrossEdge2 = Picker._tempVector32; Vector3.cross(ray.direction, edge2, directionCrossEdge2); var determinant; determinant = Vector3.dot(edge1, directionCrossEdge2); if (determinant > -Number.MIN_VALUE && determinant < Number.MIN_VALUE) { result = Number.NaN; return result; } var inverseDeterminant = 1.0 / determinant; var distanceVector = Picker._tempVector33; Vector3.subtract(ray.origin, vertex1, distanceVector); var triangleU; triangleU = Vector3.dot(distanceVector, directionCrossEdge2); triangleU *= inverseDeterminant; if (triangleU < 0 || triangleU > 1) { result = Number.NaN; return result; } var distanceCrossEdge1 = Picker._tempVector34; Vector3.cross(distanceVector, edge1, distanceCrossEdge1); var triangleV; triangleV = Vector3.dot(ray.direction, distanceCrossEdge1); triangleV *= inverseDeterminant; if (triangleV < 0 || triangleU + triangleV > 1) { result = Number.NaN; return result; } var rayDistance; rayDistance = Vector3.dot(edge2, distanceCrossEdge1); rayDistance *= inverseDeterminant; if (rayDistance < 0) { result = Number.NaN; return result; } result = rayDistance; return result; } } Picker._tempVector30 = new Vector3(); Picker._tempVector31 = new Vector3(); Picker._tempVector32 = new Vector3(); Picker._tempVector33 = new Vector3(); Picker._tempVector34 = new Vector3(); class BufferState extends Laya.BufferStateBase { constructor() { super(); } applyVertexBuffer(vertexBuffer) { if (Laya.BufferStateBase._curBindedBufferState === this) { var gl = Laya.LayaGL.instance; var verDec = vertexBuffer.vertexDeclaration; var valueData = verDec._shaderValues.getData(); this.vertexDeclaration = verDec; vertexBuffer.bind(); for (var k in valueData) { var loc = parseInt(k); var attribute = valueData[k]; gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, attribute[0], attribute[1], !!attribute[2], attribute[3], attribute[4]); } } else { throw "BufferState: must call bind() function first."; } } applyVertexBuffers(vertexBuffers) { if (Laya.BufferStateBase._curBindedBufferState === this) { var gl = Laya.LayaGL.instance; for (var i = 0, n = vertexBuffers.length; i < n; i++) { var verBuf = vertexBuffers[i]; var verDec = verBuf.vertexDeclaration; var valueData = verDec._shaderValues.getData(); verBuf.bind(); for (var k in valueData) { var loc = parseInt(k); var attribute = valueData[k]; gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, attribute[0], attribute[1], !!attribute[2], attribute[3], attribute[4]); } } } else { throw "BufferState: must call bind() function first."; } } applyInstanceVertexBuffer(vertexBuffer) { if (Laya.LayaGL.layaGPUInstance.supportInstance()) { if (Laya.BufferStateBase._curBindedBufferState === this) { var gl = Laya.LayaGL.instance; var verDec = vertexBuffer.vertexDeclaration; var valueData = verDec._shaderValues.getData(); vertexBuffer.bind(); for (var k in valueData) { var loc = parseInt(k); var attribute = valueData[k]; gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, attribute[0], attribute[1], !!attribute[2], attribute[3], attribute[4]); Laya.LayaGL.layaGPUInstance.vertexAttribDivisor(loc, 1); } } else { throw "BufferState: must call bind() function first."; } } } applyIndexBuffer(indexBuffer) { if (Laya.BufferStateBase._curBindedBufferState === this) { if (this._bindedIndexBuffer !== indexBuffer) { indexBuffer._bindForVAO(); this._bindedIndexBuffer = indexBuffer; } } else { throw "BufferState: must call bind() function first."; } } } (function (IndexFormat) { IndexFormat[IndexFormat["UInt8"] = 0] = "UInt8"; IndexFormat[IndexFormat["UInt16"] = 1] = "UInt16"; IndexFormat[IndexFormat["UInt32"] = 2] = "UInt32"; })(exports.IndexFormat || (exports.IndexFormat = {})); class IndexBuffer3D extends Laya.Buffer { constructor(indexType, indexCount, bufferUsage = 0x88E4, canRead = false) { super(); this._indexType = indexType; this._indexCount = indexCount; this._bufferUsage = bufferUsage; this._bufferType = Laya.LayaGL.instance.ELEMENT_ARRAY_BUFFER; this._canRead = canRead; switch (indexType) { case exports.IndexFormat.UInt32: this._indexTypeByteCount = 4; break; case exports.IndexFormat.UInt16: this._indexTypeByteCount = 2; break; case exports.IndexFormat.UInt8: this._indexTypeByteCount = 1; break; default: throw new Error("unidentification index type."); } var byteLength = this._indexTypeByteCount * indexCount; var curBufSta = Laya.BufferStateBase._curBindedBufferState; this._byteLength = byteLength; if (curBufSta) { if (curBufSta._bindedIndexBuffer === this) { Laya.LayaGL.instance.bufferData(this._bufferType, byteLength, this._bufferUsage); } else { curBufSta.unBind(); this.bind(); Laya.LayaGL.instance.bufferData(this._bufferType, byteLength, this._bufferUsage); curBufSta.bind(); } } else { this.bind(); Laya.LayaGL.instance.bufferData(this._bufferType, byteLength, this._bufferUsage); } if (canRead) { switch (indexType) { case exports.IndexFormat.UInt32: this._buffer = new Uint32Array(indexCount); break; case exports.IndexFormat.UInt16: this._buffer = new Uint16Array(indexCount); break; case exports.IndexFormat.UInt8: this._buffer = new Uint8Array(indexCount); break; } } } get indexType() { return this._indexType; } get indexTypeByteCount() { return this._indexTypeByteCount; } get indexCount() { return this._indexCount; } get canRead() { return this._canRead; } _bindForVAO() { if (Laya.BufferStateBase._curBindedBufferState) { var gl = Laya.LayaGL.instance; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._glBuffer); } else { throw "IndexBuffer3D: must bind current BufferState."; } } bind() { if (Laya.BufferStateBase._curBindedBufferState) { throw "IndexBuffer3D: must unbind current BufferState."; } else { if (Laya.Buffer._bindedIndexBuffer !== this._glBuffer) { var gl = Laya.LayaGL.instance; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._glBuffer); Laya.Buffer._bindedIndexBuffer = this._glBuffer; return true; } else { return false; } } } setData(data, bufferOffset = 0, dataStartIndex = 0, dataCount = 4294967295) { var byteCount = this._indexTypeByteCount; if (dataStartIndex !== 0 || dataCount !== 4294967295) { switch (this._indexType) { case exports.IndexFormat.UInt32: data = new Uint32Array(data.buffer, dataStartIndex * byteCount, dataCount); break; case exports.IndexFormat.UInt16: data = new Uint16Array(data.buffer, dataStartIndex * byteCount, dataCount); break; case exports.IndexFormat.UInt8: data = new Uint8Array(data.buffer, dataStartIndex * byteCount, dataCount); break; } } var curBufSta = Laya.BufferStateBase._curBindedBufferState; if (curBufSta) { if (curBufSta._bindedIndexBuffer === this) { Laya.LayaGL.instance.bufferSubData(this._bufferType, bufferOffset * byteCount, data); } else { curBufSta.unBind(); this.bind(); Laya.LayaGL.instance.bufferSubData(this._bufferType, bufferOffset * byteCount, data); curBufSta.bind(); } } else { this.bind(); Laya.LayaGL.instance.bufferSubData(this._bufferType, bufferOffset * byteCount, data); } if (this._canRead) { if (bufferOffset !== 0 || dataStartIndex !== 0 || dataCount !== 4294967295) { var maxLength = this._buffer.length - bufferOffset; if (dataCount > maxLength) dataCount = maxLength; for (var i = 0; i < dataCount; i++) this._buffer[bufferOffset + i] = data[i]; } else { this._buffer = data; } } } getData() { if (this._canRead) return this._buffer; else throw new Error("Can't read data from VertexBuffer with only write flag!"); } destroy() { super.destroy(); this._buffer = null; } } class VertexElementFormat { static __init__() { var gl = Laya.LayaGL.instance; VertexElementFormat._elementInfos = { "single": [1, gl.FLOAT, 0], "vector2": [2, gl.FLOAT, 0], "vector3": [3, gl.FLOAT, 0], "vector4": [4, gl.FLOAT, 0], "color": [4, gl.FLOAT, 0], "byte4": [4, gl.UNSIGNED_BYTE, 0], "short2": [2, gl.FLOAT, 0], "short4": [4, gl.FLOAT, 0], "normalizedshort2": [2, gl.FLOAT, 0], "normalizedshort4": [4, gl.FLOAT, 0], "halfvector2": [2, gl.FLOAT, 0], "halfvector4": [4, gl.FLOAT, 0] }; } static getElementInfos(element) { var info = VertexElementFormat._elementInfos[element]; if (info) return info; else throw "VertexElementFormat: this vertexElementFormat is not implement."; } } VertexElementFormat.Single = "single"; VertexElementFormat.Vector2 = "vector2"; VertexElementFormat.Vector3 = "vector3"; VertexElementFormat.Vector4 = "vector4"; VertexElementFormat.Color = "color"; VertexElementFormat.Byte4 = "byte4"; VertexElementFormat.Short2 = "short2"; VertexElementFormat.Short4 = "short4"; VertexElementFormat.NormalizedShort2 = "normalizedshort2"; VertexElementFormat.NormalizedShort4 = "normalizedshort4"; VertexElementFormat.HalfVector2 = "halfvector2"; VertexElementFormat.HalfVector4 = "halfvector4"; class VertexDeclaration { constructor(vertexStride, vertexElements) { this._id = ++VertexDeclaration._uniqueIDCounter; this._vertexElementsDic = {}; this._vertexStride = vertexStride; this._vertexElements = vertexElements; var count = vertexElements.length; this._shaderValues = new ShaderData(null); for (var j = 0; j < count; j++) { var vertexElement = vertexElements[j]; var name = vertexElement._elementUsage; this._vertexElementsDic[name] = vertexElement; var value = new Int32Array(5); var elmentInfo = VertexElementFormat.getElementInfos(vertexElement._elementFormat); value[0] = elmentInfo[0]; value[1] = elmentInfo[1]; value[2] = elmentInfo[2]; value[3] = this._vertexStride; value[4] = vertexElement._offset; this._shaderValues.setAttribute(name, value); } } get id() { return this._id; } get vertexStride() { return this._vertexStride; } get vertexElementCount() { return this._vertexElements.length; } getVertexElementByIndex(index) { return this._vertexElements[index]; } getVertexElementByUsage(usage) { return this._vertexElementsDic[usage]; } } VertexDeclaration._uniqueIDCounter = 1; class VertexElement { constructor(offset, elementFormat, elementUsage) { this._offset = offset; this._elementFormat = elementFormat; this._elementUsage = elementUsage; } get offset() { return this._offset; } get elementFormat() { return this._elementFormat; } get elementUsage() { return this._elementUsage; } } class VertexMesh { static __init__() { VertexMesh.instanceWorldMatrixDeclaration = new VertexDeclaration(64, [new VertexElement(0, VertexElementFormat.Vector4, VertexMesh.MESH_WORLDMATRIX_ROW0), new VertexElement(16, VertexElementFormat.Vector4, VertexMesh.MESH_WORLDMATRIX_ROW1), new VertexElement(32, VertexElementFormat.Vector4, VertexMesh.MESH_WORLDMATRIX_ROW2), new VertexElement(48, VertexElementFormat.Vector4, VertexMesh.MESH_WORLDMATRIX_ROW3)]); VertexMesh.instanceMVPMatrixDeclaration = new VertexDeclaration(64, [new VertexElement(0, VertexElementFormat.Vector4, VertexMesh.MESH_MVPMATRIX_ROW0), new VertexElement(16, VertexElementFormat.Vector4, VertexMesh.MESH_MVPMATRIX_ROW1), new VertexElement(32, VertexElementFormat.Vector4, VertexMesh.MESH_MVPMATRIX_ROW2), new VertexElement(48, VertexElementFormat.Vector4, VertexMesh.MESH_MVPMATRIX_ROW3)]); } static getVertexDeclaration(vertexFlag, compatible = true) { var verDec = VertexMesh._vertexDeclarationMap[vertexFlag + (compatible ? "_0" : "_1")]; if (!verDec) { var subFlags = vertexFlag.split(","); var offset = 0; var elements = []; for (var i = 0, n = subFlags.length; i < n; i++) { var element; switch (subFlags[i]) { case "POSITION": element = new VertexElement(offset, VertexElementFormat.Vector3, VertexMesh.MESH_POSITION0); offset += 12; break; case "NORMAL": element = new VertexElement(offset, VertexElementFormat.Vector3, VertexMesh.MESH_NORMAL0); offset += 12; break; case "COLOR": element = new VertexElement(offset, VertexElementFormat.Vector4, VertexMesh.MESH_COLOR0); offset += 16; break; case "UV": element = new VertexElement(offset, VertexElementFormat.Vector2, VertexMesh.MESH_TEXTURECOORDINATE0); offset += 8; break; case "UV1": element = new VertexElement(offset, VertexElementFormat.Vector2, VertexMesh.MESH_TEXTURECOORDINATE1); offset += 8; break; case "BLENDWEIGHT": element = new VertexElement(offset, VertexElementFormat.Vector4, VertexMesh.MESH_BLENDWEIGHT0); offset += 16; break; case "BLENDINDICES": if (compatible) { element = new VertexElement(offset, VertexElementFormat.Vector4, VertexMesh.MESH_BLENDINDICES0); offset += 16; } else { element = new VertexElement(offset, VertexElementFormat.Byte4, VertexMesh.MESH_BLENDINDICES0); offset += 4; } break; case "TANGENT": element = new VertexElement(offset, VertexElementFormat.Vector4, VertexMesh.MESH_TANGENT0); offset += 16; break; default: throw "VertexMesh: unknown vertex flag."; } elements.push(element); } verDec = new VertexDeclaration(offset, elements); VertexMesh._vertexDeclarationMap[vertexFlag + (compatible ? "_0" : "_1")] = verDec; } return verDec; } } VertexMesh.MESH_POSITION0 = 0; VertexMesh.MESH_COLOR0 = 1; VertexMesh.MESH_TEXTURECOORDINATE0 = 2; VertexMesh.MESH_NORMAL0 = 3; VertexMesh.MESH_TANGENT0 = 4; VertexMesh.MESH_BLENDINDICES0 = 5; VertexMesh.MESH_BLENDWEIGHT0 = 6; VertexMesh.MESH_TEXTURECOORDINATE1 = 7; VertexMesh.MESH_WORLDMATRIX_ROW0 = 8; VertexMesh.MESH_WORLDMATRIX_ROW1 = 9; VertexMesh.MESH_WORLDMATRIX_ROW2 = 10; VertexMesh.MESH_WORLDMATRIX_ROW3 = 11; VertexMesh.MESH_MVPMATRIX_ROW0 = 12; VertexMesh.MESH_MVPMATRIX_ROW1 = 13; VertexMesh.MESH_MVPMATRIX_ROW2 = 14; VertexMesh.MESH_MVPMATRIX_ROW3 = 15; VertexMesh._vertexDeclarationMap = {}; class VertexBuffer3D extends Laya.Buffer { constructor(byteLength, bufferUsage, canRead = false) { super(); this._vertexDeclaration = null; this._float32Reader = null; var gl = Laya.LayaGL.instance; this._bufferUsage = bufferUsage; this._bufferType = gl.ARRAY_BUFFER; this._canRead = canRead; this._byteLength = byteLength; this.bind(); gl.bufferData(this._bufferType, this._byteLength, this._bufferUsage); if (canRead) { this._buffer = new Uint8Array(byteLength); this._float32Reader = new Float32Array(this._buffer.buffer); } } get vertexDeclaration() { return this._vertexDeclaration; } set vertexDeclaration(value) { this._vertexDeclaration = value; } get canRead() { return this._canRead; } bind() { if (Laya.Buffer._bindedVertexBuffer !== this._glBuffer) { var gl = Laya.LayaGL.instance; gl.bindBuffer(gl.ARRAY_BUFFER, this._glBuffer); Laya.Buffer._bindedVertexBuffer = this._glBuffer; return true; } else { return false; } } orphanStorage() { this.bind(); Laya.LayaGL.instance.bufferData(this._bufferType, this._byteLength, this._bufferUsage); } setData(buffer, bufferOffset = 0, dataStartIndex = 0, dataCount = Number.MAX_SAFE_INTEGER) { this.bind(); var needSubData = dataStartIndex !== 0 || dataCount !== Number.MAX_SAFE_INTEGER; if (needSubData) { var subData = new Uint8Array(buffer, dataStartIndex, dataCount); Laya.LayaGL.instance.bufferSubData(this._bufferType, bufferOffset, subData); if (this._canRead) this._buffer.set(subData, bufferOffset); } else { Laya.LayaGL.instance.bufferSubData(this._bufferType, bufferOffset, buffer); if (this._canRead) this._buffer.set(new Uint8Array(buffer), bufferOffset); } } getUint8Data() { if (this._canRead) return this._buffer; else throw new Error("Can't read data from VertexBuffer with only write flag!"); } getFloat32Data() { if (this._canRead) return this._float32Reader; else throw new Error("Can't read data from VertexBuffer with only write flag!"); } markAsUnreadbale() { this._canRead = false; this._buffer = null; this._float32Reader = null; } destroy() { super.destroy(); this._buffer = null; this._float32Reader = null; this._vertexDeclaration = null; } } VertexBuffer3D.DATATYPE_FLOAT32ARRAY = 0; VertexBuffer3D.DATATYPE_UINT8ARRAY = 1; class SkyMesh { constructor() { } _render(state) { } } class SkyBox extends SkyMesh { constructor() { super(); var gl = Laya.LayaGL.instance; var halfHeight = 1.0; var halfWidth = 1.0; var halfDepth = 1.0; var vertices = new Float32Array([-halfDepth, halfHeight, -halfWidth, halfDepth, halfHeight, -halfWidth, halfDepth, halfHeight, halfWidth, -halfDepth, halfHeight, halfWidth, -halfDepth, -halfHeight, -halfWidth, halfDepth, -halfHeight, -halfWidth, halfDepth, -halfHeight, halfWidth, -halfDepth, -halfHeight, halfWidth]); var indices = new Uint8Array([ 0, 1, 2, 2, 3, 0, 4, 7, 6, 6, 5, 4, 0, 3, 7, 7, 4, 0, 1, 5, 6, 6, 2, 1, 3, 2, 6, 6, 7, 3, 0, 4, 5, 5, 1, 0 ]); var verDec = VertexMesh.getVertexDeclaration("POSITION"); this._vertexBuffer = new VertexBuffer3D(verDec.vertexStride * 8, gl.STATIC_DRAW, false); this._vertexBuffer.vertexDeclaration = verDec; this._indexBuffer = new IndexBuffer3D(exports.IndexFormat.UInt8, 36, gl.STATIC_DRAW, false); this._vertexBuffer.setData(vertices.buffer); this._indexBuffer.setData(indices); var bufferState = new BufferState(); bufferState.bind(); bufferState.applyVertexBuffer(this._vertexBuffer); bufferState.applyIndexBuffer(this._indexBuffer); bufferState.unBind(); this._bufferState = bufferState; } static __init__() { SkyBox.instance = new SkyBox(); } _render(state) { var gl = Laya.LayaGL.instance; gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0); Laya.Stat.trianglesFaces += 12; Laya.Stat.renderBatches++; } } class SkyRenderer { constructor() { this._mesh = SkyBox.instance; } get material() { return this._material; } set material(value) { if (this._material !== value) { (this._material) && (this._material._removeReference()); (value) && (value._addReference()); this._material = value; } } get mesh() { return this._mesh; } set mesh(value) { if (this._mesh !== value) { this._mesh = value; } } _isAvailable() { return this._material && this._mesh ? true : false; } _render(context) { if (this._material && this._mesh) { var gl = Laya.LayaGL.instance; var scene = context.scene; var cameraShaderValue = context.cameraShaderValue; var camera = context.camera; var noteValue = ShaderData._SET_RUNTIME_VALUE_MODE_REFERENCE_; Laya.ILaya.Render.supportWebGLPlusRendering && ShaderData.setRuntimeValueMode(false); Laya.WebGLContext.setCullFace(gl, false); Laya.WebGLContext.setDepthFunc(gl, gl.LEQUAL); Laya.WebGLContext.setDepthMask(gl, false); var comDef = SkyRenderer._compileDefine; this._material._shaderValues._defineDatas.cloneTo(comDef); var shader = context.shader = this._material._shader.getSubShaderAt(0)._passes[0].withCompile(comDef); var switchShader = shader.bind(); var switchShaderLoop = (Laya.Stat.loopCount !== shader._uploadMark); var uploadScene = (shader._uploadScene !== scene) || switchShaderLoop; if (uploadScene || switchShader) { shader.uploadUniforms(shader._sceneUniformParamsMap, scene._shaderValues, uploadScene); shader._uploadScene = scene; } var renderTex = camera._getRenderTexture(); var uploadCamera = (shader._uploadCameraShaderValue !== cameraShaderValue) || switchShaderLoop; if (uploadCamera || switchShader) { var viewMatrix = SkyRenderer._tempMatrix0; var projectionMatrix = SkyRenderer._tempMatrix1; camera.viewMatrix.cloneTo(viewMatrix); camera.projectionMatrix.cloneTo(projectionMatrix); viewMatrix.setTranslationVector(Vector3._ZERO); if (camera.orthographic) Matrix4x4.createPerspective(camera.fieldOfView, camera.aspectRatio, camera.nearPlane, camera.farPlane, projectionMatrix); var epsilon = 1e-6; var yScale = 1.0 / Math.tan(3.1416 * camera.fieldOfView / 180 * 0.5); projectionMatrix.elements[0] = yScale / camera.aspectRatio; projectionMatrix.elements[5] = yScale; projectionMatrix.elements[10] = epsilon - 1.0; projectionMatrix.elements[11] = -1.0; projectionMatrix.elements[14] = -0; camera._applyViewProject(context, viewMatrix, projectionMatrix); shader.uploadUniforms(shader._cameraUniformParamsMap, cameraShaderValue, uploadCamera); shader._uploadCameraShaderValue = cameraShaderValue; } var uploadMaterial = (shader._uploadMaterial !== this._material) || switchShaderLoop; if (uploadMaterial || switchShader) { shader.uploadUniforms(shader._materialUniformParamsMap, this._material._shaderValues, uploadMaterial); shader._uploadMaterial = this._material; } this._mesh._bufferState.bind(); this._mesh._render(context); Laya.ILaya.Render.supportWebGLPlusRendering && ShaderData.setRuntimeValueMode(noteValue); Laya.WebGLContext.setDepthFunc(gl, gl.LESS); Laya.WebGLContext.setDepthMask(gl, true); camera._applyViewProject(context, camera.viewMatrix, camera.projectionMatrix); } } destroy() { if (this._material) { this._material._removeReference(); this._material = null; } } } SkyRenderer._tempMatrix0 = new Matrix4x4(); SkyRenderer._tempMatrix1 = new Matrix4x4(); SkyRenderer._compileDefine = new DefineDatas(); class Sprite3D extends Laya.Node { constructor(name = null, isStatic = false) { super(); this._needProcessCollisions = false; this._needProcessTriggers = false; this._id = ++Sprite3D._uniqueIDCounter; this._transform = new Transform3D(this); this._isStatic = isStatic; this.layer = 0; this.name = name ? name : "New Sprite3D"; } static __init__() { } static instantiate(original, parent = null, worldPositionStays = true, position = null, rotation = null) { var destSprite3D = original.clone(); (parent) && (parent.addChild(destSprite3D)); var transform = destSprite3D.transform; if (worldPositionStays) { var worldMatrix = transform.worldMatrix; original.transform.worldMatrix.cloneTo(worldMatrix); transform.worldMatrix = worldMatrix; } else { (position) && (transform.position = position); (rotation) && (transform.rotation = rotation); } return destSprite3D; } static load(url, complete) { Laya.Laya.loader.create(url, complete, null, Sprite3D.HIERARCHY); } get id() { return this._id; } get layer() { return this._layer; } set layer(value) { if (this._layer !== value) { if (value >= 0 && value <= 30) { this._layer = value; } else { throw new Error("Layer value must be 0-30."); } } } get url() { return this._url; } get isStatic() { return this._isStatic; } get transform() { return this._transform; } _setCreateURL(url) { this._url = Laya.URL.formatURL(url); } _changeAnimatorsToLinkSprite3D(sprite3D, isLink, path) { var animator = this.getComponent(Animator); if (animator) { if (!animator.avatar) sprite3D._changeAnimatorToLinkSprite3DNoAvatar(animator, isLink, path); } if (this._parent && this._parent instanceof Sprite3D) { path.unshift(this._parent.name); var p = this._parent; (p._hierarchyAnimator) && (p._changeAnimatorsToLinkSprite3D(sprite3D, isLink, path)); } } _setHierarchyAnimator(animator, parentAnimator) { this._changeHierarchyAnimator(animator); this._changeAnimatorAvatar(animator.avatar); for (var i = 0, n = this._children.length; i < n; i++) { var child = this._children[i]; (child._hierarchyAnimator == parentAnimator) && (child._setHierarchyAnimator(animator, parentAnimator)); } } _clearHierarchyAnimator(animator, parentAnimator) { this._changeHierarchyAnimator(parentAnimator); this._changeAnimatorAvatar(parentAnimator ? parentAnimator.avatar : null); for (var i = 0, n = this._children.length; i < n; i++) { var child = this._children[i]; (child._hierarchyAnimator == animator) && (child._clearHierarchyAnimator(animator, parentAnimator)); } } _changeHierarchyAnimatorAvatar(animator, avatar) { this._changeAnimatorAvatar(avatar); for (var i = 0, n = this._children.length; i < n; i++) { var child = this._children[i]; (child._hierarchyAnimator == animator) && (child._changeHierarchyAnimatorAvatar(animator, avatar)); } } _changeAnimatorToLinkSprite3DNoAvatar(animator, isLink, path) { animator._handleSpriteOwnersBySprite(isLink, path, this); for (var i = 0, n = this._children.length; i < n; i++) { var child = this._children[i]; var index = path.length; path.push(child.name); child._changeAnimatorToLinkSprite3DNoAvatar(animator, isLink, path); path.splice(index, 1); } } _changeHierarchyAnimator(animator) { this._hierarchyAnimator = animator; } _changeAnimatorAvatar(avatar) { } _onAdded() { if (this._parent instanceof Sprite3D) { var parent3D = this._parent; this.transform._setParent(parent3D.transform); if (parent3D._hierarchyAnimator) { (!this._hierarchyAnimator) && (this._setHierarchyAnimator(parent3D._hierarchyAnimator, null)); parent3D._changeAnimatorsToLinkSprite3D(this, true, [this.name]); } } super._onAdded(); } _onRemoved() { super._onRemoved(); if (this._parent instanceof Sprite3D) { var parent3D = this._parent; this.transform._setParent(null); if (parent3D._hierarchyAnimator) { (this._hierarchyAnimator == parent3D._hierarchyAnimator) && (this._clearHierarchyAnimator(parent3D._hierarchyAnimator, null)); parent3D._changeAnimatorsToLinkSprite3D(this, false, [this.name]); } } } _parse(data, spriteMap) { (data.isStatic !== undefined) && (this._isStatic = data.isStatic); (data.active !== undefined) && (this.active = data.active); (data.name != undefined) && (this.name = data.name); if (data.position !== undefined) { var loccalPosition = this.transform.localPosition; loccalPosition.fromArray(data.position); this.transform.localPosition = loccalPosition; } if (data.rotationEuler !== undefined) { var localRotationEuler = this.transform.localRotationEuler; localRotationEuler.fromArray(data.rotationEuler); this.transform.localRotationEuler = localRotationEuler; } if (data.rotation !== undefined) { var localRotation = this.transform.localRotation; localRotation.fromArray(data.rotation); this.transform.localRotation = localRotation; } if (data.scale !== undefined) { var localScale = this.transform.localScale; localScale.fromArray(data.scale); this.transform.localScale = localScale; } (data.layer != undefined) && (this.layer = data.layer); } _cloneTo(destObject, srcRoot, dstRoot) { if (this.destroyed) throw new Error("Sprite3D: Can't be cloned if the Sprite3D has destroyed."); var destSprite3D = destObject; var trans = this._transform; var destTrans = destSprite3D._transform; destSprite3D.name = this.name; destSprite3D.destroyed = this.destroyed; destSprite3D.active = this.active; destTrans.localPosition = trans.localPosition; destTrans.localRotation = trans.localRotation; destTrans.localScale = trans.localScale; destSprite3D._isStatic = this._isStatic; destSprite3D.layer = this.layer; super._cloneTo(destSprite3D, srcRoot, dstRoot); } static _createSprite3DInstance(scrSprite) { var node = scrSprite._create(); var children = scrSprite._children; for (var i = 0, n = children.length; i < n; i++) { var child = Sprite3D._createSprite3DInstance(children[i]); node.addChild(child); } return node; } static _parseSprite3DInstance(srcRoot, dstRoot, scrSprite, dstSprite) { var srcChildren = scrSprite._children; var dstChildren = dstSprite._children; for (var i = 0, n = srcChildren.length; i < n; i++) Sprite3D._parseSprite3DInstance(srcRoot, dstRoot, srcChildren[i], dstChildren[i]); scrSprite._cloneTo(dstSprite, srcRoot, dstRoot); } clone() { var dstSprite3D = Sprite3D._createSprite3DInstance(this); Sprite3D._parseSprite3DInstance(this, dstSprite3D, this, dstSprite3D); return dstSprite3D; } destroy(destroyChild = true) { if (this.destroyed) return; super.destroy(destroyChild); this._transform = null; this._scripts = null; this._url && Laya.Loader.clearRes(this._url); } _create() { return new Sprite3D(); } } Sprite3D.HIERARCHY = "HIERARCHY"; Sprite3D.WORLDMATRIX = Shader3D.propertyNameToID("u_WorldMat"); Sprite3D.MVPMATRIX = Shader3D.propertyNameToID("u_MvpMatrix"); Sprite3D._uniqueIDCounter = 0; class BaseCamera extends Sprite3D { constructor(nearPlane = 0.3, farPlane = 1000) { super(); this._skyRenderer = new SkyRenderer(); this._forward = new Vector3(); this._up = new Vector3(); this.clearColor = new Vector4(100 / 255, 149 / 255, 237 / 255, 255 / 255); this._shaderValues = new ShaderData(null); this._fieldOfView = 60; this._useUserProjectionMatrix = false; this._orthographic = false; this._orthographicVerticalSize = 10; this.renderingOrder = 0; this._nearPlane = nearPlane; this._farPlane = farPlane; this.cullingMask = 2147483647; this.useOcclusionCulling = true; } get skyRenderer() { return this._skyRenderer; } get fieldOfView() { return this._fieldOfView; } set fieldOfView(value) { this._fieldOfView = value; this._calculateProjectionMatrix(); } get nearPlane() { return this._nearPlane; } set nearPlane(value) { this._nearPlane = value; this._calculateProjectionMatrix(); } get farPlane() { return this._farPlane; } set farPlane(vaule) { this._farPlane = vaule; this._calculateProjectionMatrix(); } get orthographic() { return this._orthographic; } set orthographic(vaule) { this._orthographic = vaule; this._calculateProjectionMatrix(); } get orthographicVerticalSize() { return this._orthographicVerticalSize; } set orthographicVerticalSize(vaule) { this._orthographicVerticalSize = vaule; this._calculateProjectionMatrix(); } get renderingOrder() { return this._renderingOrder; } set renderingOrder(value) { this._renderingOrder = value; this._sortCamerasByRenderingOrder(); } _sortCamerasByRenderingOrder() { if (this.displayedInStage) { var cameraPool = this.scene._cameraPool; var n = cameraPool.length - 1; for (var i = 0; i < n; i++) { if (cameraPool[i].renderingOrder > cameraPool[n].renderingOrder) { var tempCamera = cameraPool[i]; cameraPool[i] = cameraPool[n]; cameraPool[n] = tempCamera; } } } } _calculateProjectionMatrix() { } _onScreenSizeChanged() { this._calculateProjectionMatrix(); } _prepareCameraToRender() { var cameraSV = this._shaderValues; this.transform.getForward(this._forward); this.transform.getUp(this._up); cameraSV.setVector3(BaseCamera.CAMERAPOS, this.transform.position); cameraSV.setVector3(BaseCamera.CAMERADIRECTION, this._forward); cameraSV.setVector3(BaseCamera.CAMERAUP, this._up); } render(shader = null, replacementTag = null) { } addLayer(layer) { this.cullingMask |= Math.pow(2, layer); } removeLayer(layer) { this.cullingMask &= ~Math.pow(2, layer); } addAllLayers() { this.cullingMask = 2147483647; } removeAllLayers() { this.cullingMask = 0; } resetProjectionMatrix() { this._useUserProjectionMatrix = false; this._calculateProjectionMatrix(); } _onActive() { this._scene._addCamera(this); super._onActive(); } _onInActive() { this._scene._removeCamera(this); super._onInActive(); } _parse(data, spriteMap) { super._parse(data, spriteMap); this.orthographic = data.orthographic; (data.orthographicVerticalSize !== undefined) && (this.orthographicVerticalSize = data.orthographicVerticalSize); (data.fieldOfView !== undefined) && (this.fieldOfView = data.fieldOfView); this.nearPlane = data.nearPlane; this.farPlane = data.farPlane; var color = data.clearColor; this.clearColor = new Vector4(color[0], color[1], color[2], color[3]); var skyboxMaterial = data.skyboxMaterial; if (skyboxMaterial) { this._skyRenderer.material = Laya.Loader.getRes(skyboxMaterial.path); } } destroy(destroyChild = true) { this._skyRenderer.destroy(); this._skyRenderer = null; Laya.Laya.stage.off(Laya.Event.RESIZE, this, this._onScreenSizeChanged); super.destroy(destroyChild); } _create() { return new BaseCamera(); } } BaseCamera._tempMatrix4x40 = new Matrix4x4(); BaseCamera.CAMERAPOS = Shader3D.propertyNameToID("u_CameraPos"); BaseCamera.VIEWMATRIX = Shader3D.propertyNameToID("u_View"); BaseCamera.PROJECTMATRIX = Shader3D.propertyNameToID("u_Projection"); BaseCamera.VIEWPROJECTMATRIX = Shader3D.propertyNameToID("u_ViewProjection"); BaseCamera.CAMERADIRECTION = Shader3D.propertyNameToID("u_CameraDirection"); BaseCamera.CAMERAUP = Shader3D.propertyNameToID("u_CameraUp"); BaseCamera.VIEWPORT = Shader3D.propertyNameToID("u_Viewport"); BaseCamera.PROJECTION_PARAMS = Shader3D.propertyNameToID("u_ProjectionParams"); BaseCamera.RENDERINGTYPE_DEFERREDLIGHTING = "DEFERREDLIGHTING"; BaseCamera.RENDERINGTYPE_FORWARDRENDERING = "FORWARDRENDERING"; BaseCamera._invertYScaleMatrix = new Matrix4x4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); BaseCamera._invertYProjectionMatrix = new Matrix4x4(); BaseCamera._invertYProjectionViewMatrix = new Matrix4x4(); BaseCamera.CLEARFLAG_SOLIDCOLOR = 0; BaseCamera.CLEARFLAG_SKY = 1; BaseCamera.CLEARFLAG_DEPTHONLY = 2; BaseCamera.CLEARFLAG_NONE = 3; (function (ShadowMode) { ShadowMode[ShadowMode["None"] = 0] = "None"; ShadowMode[ShadowMode["Hard"] = 1] = "Hard"; ShadowMode[ShadowMode["SoftLow"] = 2] = "SoftLow"; ShadowMode[ShadowMode["SoftHigh"] = 3] = "SoftHigh"; })(exports.ShadowMode || (exports.ShadowMode = {})); class ScreenQuad extends Laya.Resource { constructor() { super(); this._bufferState = new BufferState(); this._bufferStateInvertUV = new BufferState(); var gl = Laya.LayaGL.instance; this._vertexBuffer = new VertexBuffer3D(16 * 4, gl.STATIC_DRAW, false); this._vertexBuffer.vertexDeclaration = ScreenQuad._vertexDeclaration; this._vertexBuffer.setData(ScreenQuad._vertices.buffer); this._bufferState.bind(); this._bufferState.applyVertexBuffer(this._vertexBuffer); this._bufferState.unBind(); this._vertexBufferInvertUV = new VertexBuffer3D(16 * 4, gl.STATIC_DRAW, false); this._vertexBufferInvertUV.vertexDeclaration = ScreenQuad._vertexDeclaration; this._vertexBufferInvertUV.setData(ScreenQuad._verticesInvertUV.buffer); this._bufferStateInvertUV.bind(); this._bufferStateInvertUV.applyVertexBuffer(this._vertexBufferInvertUV); this._bufferStateInvertUV.unBind(); this._setGPUMemory(this._vertexBuffer._byteLength + this._vertexBufferInvertUV._byteLength); } static __init__() { ScreenQuad._vertexDeclaration = new VertexDeclaration(16, [new VertexElement(0, VertexElementFormat.Vector4, ScreenQuad.SCREENQUAD_POSITION_UV)]); ScreenQuad.instance = new ScreenQuad(); ScreenQuad.instance.lock = true; } render() { var gl = Laya.LayaGL.instance; this._bufferState.bind(); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); Laya.Stat.renderBatches++; } renderInvertUV() { var gl = Laya.LayaGL.instance; this._bufferStateInvertUV.bind(); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); Laya.Stat.renderBatches++; } destroy() { super.destroy(); this._bufferState.destroy(); this._vertexBuffer.destroy(); this._bufferStateInvertUV.destroy(); this._vertexBufferInvertUV.destroy(); this._setGPUMemory(0); } } ScreenQuad.SCREENQUAD_POSITION_UV = 0; ScreenQuad._vertices = new Float32Array([1, 1, 1, 1, 1, -1, 1, 0, -1, 1, 0, 1, -1, -1, 0, 0]); ScreenQuad._verticesInvertUV = new Float32Array([1, 1, 1, 0, 1, -1, 1, 1, -1, 1, 0, 0, -1, -1, 0, 1]); class ScreenTriangle extends Laya.Resource { constructor() { super(); this._bufferState = new BufferState(); this._bufferStateInvertUV = new BufferState(); var gl = Laya.LayaGL.instance; this._vertexBuffer = new VertexBuffer3D(12 * 4, gl.STATIC_DRAW, false); this._vertexBuffer.vertexDeclaration = ScreenTriangle._vertexDeclaration; this._vertexBuffer.setData(ScreenTriangle._vertices.buffer); this._bufferState.bind(); this._bufferState.applyVertexBuffer(this._vertexBuffer); this._bufferState.unBind(); this._vertexBufferInvertUV = new VertexBuffer3D(12 * 4, gl.STATIC_DRAW, false); this._vertexBufferInvertUV.vertexDeclaration = ScreenTriangle._vertexDeclaration; this._vertexBufferInvertUV.setData(ScreenTriangle._verticesInvertUV.buffer); this._bufferStateInvertUV.bind(); this._bufferStateInvertUV.applyVertexBuffer(this._vertexBufferInvertUV); this._bufferStateInvertUV.unBind(); this._setGPUMemory(this._vertexBuffer._byteLength + this._vertexBufferInvertUV._byteLength); } static __init__() { ScreenTriangle._vertexDeclaration = new VertexDeclaration(16, [new VertexElement(0, VertexElementFormat.Vector4, ScreenTriangle.SCREENTRIANGLE_POSITION_UV)]); ScreenTriangle.instance = new ScreenTriangle(); ScreenTriangle.instance.lock = true; } render() { var gl = Laya.LayaGL.instance; this._bufferState.bind(); gl.drawArrays(gl.TRIANGLES, 0, 3); Laya.Stat.renderBatches++; } renderInvertUV() { var gl = Laya.LayaGL.instance; this._bufferStateInvertUV.bind(); gl.drawArrays(gl.TRIANGLES, 0, 3); Laya.Stat.renderBatches++; } destroy() { super.destroy(); this._bufferState.destroy(); this._vertexBuffer.destroy(); this._bufferStateInvertUV.destroy(); this._vertexBufferInvertUV.destroy(); this._setGPUMemory(0); } } ScreenTriangle.SCREENTRIANGLE_POSITION_UV = 0; ScreenTriangle._vertices = new Float32Array([-1, -1, 0, 0, -1, 3, 0, 2, 3, -1, 2, 0]); ScreenTriangle._verticesInvertUV = new Float32Array([-1, -1, 0, 1, -1, 3, 0, -1, 3, -1, 2, 1]); class Command { constructor() { this._commandBuffer = null; } static __init__() { Command._screenShaderData = new ShaderData(); Command._screenShader = Shader3D.find("BlitScreen"); } run() { } recover() { this._commandBuffer = null; } } Command.SCREENTEXTURE_NAME = "u_MainTex"; Command.SCREENTEXTUREOFFSETSCALE_NAME = "u_OffsetScale"; Command.MAINTEXTURE_TEXELSIZE_NAME = "u_MainTex_TexelSize"; Command.SCREENTEXTURE_ID = Shader3D.propertyNameToID(Command.SCREENTEXTURE_NAME); Command.SCREENTEXTUREOFFSETSCALE_ID = Shader3D.propertyNameToID(Command.SCREENTEXTUREOFFSETSCALE_NAME); Command.MAINTEXTURE_TEXELSIZE_ID = Shader3D.propertyNameToID(Command.MAINTEXTURE_TEXELSIZE_NAME); class BlitScreenQuadCMD extends Command { constructor() { super(...arguments); this._source = null; this._dest = null; this._offsetScale = null; this._shader = null; this._shaderData = null; this._subShader = 0; this._sourceTexelSize = new Vector4(); this._screenType = 0; } static create(source, dest, offsetScale = null, shader = null, shaderData = null, subShader = 0, screenType = BlitScreenQuadCMD._SCREENTYPE_QUAD) { var cmd; cmd = BlitScreenQuadCMD._pool.length > 0 ? BlitScreenQuadCMD._pool.pop() : new BlitScreenQuadCMD(); cmd._source = source; cmd._dest = dest; cmd._offsetScale = offsetScale; cmd._shader = shader; cmd._shaderData = shaderData; cmd._subShader = subShader; cmd._screenType = screenType; return cmd; } run() { var shader = this._shader || Command._screenShader; var shaderData = this._shaderData || Command._screenShaderData; var dest = this._dest; Laya.LayaGL.instance.viewport(0, 0, dest ? dest.width : RenderContext3D.clientWidth, dest ? dest.height : RenderContext3D.clientHeight); shaderData.setTexture(Command.SCREENTEXTURE_ID, this._source); shaderData.setVector(Command.SCREENTEXTUREOFFSETSCALE_ID, this._offsetScale || BlitScreenQuadCMD._defaultOffsetScale); this._sourceTexelSize.setValue(1.0 / this._source.width, 1.0 / this._source.height, this._source.width, this._source.height); shaderData.setVector(Command.MAINTEXTURE_TEXELSIZE_ID, this._sourceTexelSize); (dest) && (dest._start()); var subShader = shader.getSubShaderAt(this._subShader); var passes = subShader._passes; for (var i = 0, n = passes.length; i < n; i++) { var comDef = BlitScreenQuadCMD._compileDefine; shaderData._defineDatas.cloneTo(comDef); var shaderPass = passes[i].withCompile(comDef); shaderPass.bind(); shaderPass.uploadUniforms(shaderPass._materialUniformParamsMap, shaderData, true); shaderPass.uploadRenderStateBlendDepth(shaderData); shaderPass.uploadRenderStateFrontFace(shaderData, false, null); switch (this._screenType) { case BlitScreenQuadCMD._SCREENTYPE_QUAD: RenderContext3D._instance.invertY ? ScreenQuad.instance.renderInvertUV() : ScreenQuad.instance.render(); break; case BlitScreenQuadCMD._SCREENTYPE_TRIANGLE: RenderContext3D._instance.invertY ? ScreenTriangle.instance.renderInvertUV() : ScreenTriangle.instance.render(); break; default: throw "BlitScreenQuadCMD:unknown screen Type."; } } (dest) && (dest._end()); } recover() { BlitScreenQuadCMD._pool.push(this); this._source = null; this._dest = null; this._offsetScale = null; this._shader = null; this._shaderData = null; super.recover(); } } BlitScreenQuadCMD._SCREENTYPE_QUAD = 0; BlitScreenQuadCMD._SCREENTYPE_TRIANGLE = 1; BlitScreenQuadCMD._compileDefine = new DefineDatas(); BlitScreenQuadCMD._pool = []; BlitScreenQuadCMD._defaultOffsetScale = new Vector4(0, 0, 1, 1); class SetRenderTargetCMD extends Command { constructor() { super(...arguments); this._renderTexture = null; } static create(renderTexture) { var cmd; cmd = SetRenderTargetCMD._pool.length > 0 ? SetRenderTargetCMD._pool.pop() : new SetRenderTargetCMD(); cmd._renderTexture = renderTexture; return cmd; } run() { this._renderTexture._start(); } recover() { SetRenderTargetCMD._pool.push(this); this._renderTexture = null; } } SetRenderTargetCMD._pool = []; class SetShaderDataTextureCMD extends Command { constructor() { super(...arguments); this._shaderData = null; this._nameID = 0; this._texture = null; } static create(shaderData, nameID, texture) { var cmd; cmd = SetShaderDataTextureCMD._pool.length > 0 ? SetShaderDataTextureCMD._pool.pop() : new SetShaderDataTextureCMD(); cmd._shaderData = shaderData; cmd._nameID = nameID; cmd._texture = texture; return cmd; } run() { this._shaderData.setTexture(this._nameID, this._texture); } recover() { SetShaderDataTextureCMD._pool.push(this); this._shaderData = null; this._nameID = 0; this._texture = null; } } SetShaderDataTextureCMD._pool = []; class CommandBuffer { constructor() { this._camera = null; this._commands = []; } _apply() { for (var i = 0, n = this._commands.length; i < n; i++) this._commands[i].run(); } setShaderDataTexture(shaderData, nameID, source) { this._commands.push(SetShaderDataTextureCMD.create(shaderData, nameID, source)); } blitScreenQuad(source, dest, offsetScale = null, shader = null, shaderData = null, subShader = 0) { this._commands.push(BlitScreenQuadCMD.create(source, dest, offsetScale, shader, shaderData, subShader, BlitScreenQuadCMD._SCREENTYPE_QUAD)); } blitScreenTriangle(source, dest, offsetScale = null, shader = null, shaderData = null, subShader = 0) { this._commands.push(BlitScreenQuadCMD.create(source, dest, offsetScale, shader, shaderData, subShader, BlitScreenQuadCMD._SCREENTYPE_TRIANGLE)); } setRenderTarget(renderTexture) { this._commands.push(SetRenderTargetCMD.create(renderTexture)); } clear() { for (var i = 0, n = this._commands.length; i < n; i++) this._commands[i].recover(); this._commands.length = 0; } } class Scene3DShaderDeclaration { } (function (LightType) { LightType[LightType["Directional"] = 0] = "Directional"; LightType[LightType["Spot"] = 1] = "Spot"; LightType[LightType["Point"] = 2] = "Point"; })(exports.LightType || (exports.LightType = {})); class LightSprite extends Sprite3D { constructor() { super(); this._shadowMode = exports.ShadowMode.None; this._isAlternate = false; this._shadowResolution = 2048; this._shadowDistance = 50.0; this._shadowDepthBias = 1.0; this._shadowNormalBias = 1.0; this._shadowNearPlane = 0.1; this._shadowStrength = 1.0; this._intensity = 1.0; this._intensityColor = new Vector3(); this.color = new Vector3(1.0, 1.0, 1.0); this._lightmapBakedType = LightSprite.LIGHTMAPBAKEDTYPE_REALTIME; } get intensity() { return this._intensity; } set intensity(value) { this._intensity = value; } get shadowMode() { return this._shadowMode; } set shadowMode(value) { this._shadowMode = value; } get shadowDistance() { return this._shadowDistance; } set shadowDistance(value) { this._shadowDistance = value; } get shadowResolution() { return this._shadowResolution; } set shadowResolution(value) { this._shadowResolution = value; } get shadowDepthBias() { return this._shadowDepthBias; } set shadowDepthBias(value) { this._shadowDepthBias = value; } get shadowNormalBias() { return this._shadowNormalBias; } set shadowNormalBias(value) { this._shadowNormalBias = value; } get shadowStrength() { return this._shadowStrength; } set shadowStrength(value) { this._shadowStrength = value; } get shadowNearPlane() { return this._shadowNearPlane; } set shadowNearPlane(value) { this._shadowNearPlane = value; } get lightmapBakedType() { return this._lightmapBakedType; } set lightmapBakedType(value) { if (this._lightmapBakedType !== value) { this._lightmapBakedType = value; if (this.activeInHierarchy) { if (value !== LightSprite.LIGHTMAPBAKEDTYPE_BAKED) this._addToScene(); else this._removeFromScene(); } } } _parse(data, spriteMap) { super._parse(data, spriteMap); var colorData = data.color; this.color.fromArray(colorData); this.intensity = data.intensity; this.lightmapBakedType = data.lightmapBakedType; } _addToScene() { var scene = this._scene; var maxLightCount = Config3D._config.maxLightCount; if (scene._lightCount < maxLightCount) { scene._lightCount++; this._addToLightQueue(); this._isAlternate = false; } else { scene._alternateLights.add(this); this._isAlternate = true; console.warn("LightSprite:light count has large than maxLightCount,the latest added light will be ignore."); } } _removeFromScene() { var scene = this._scene; if (this._isAlternate) { scene._alternateLights.remove(this); } else { scene._lightCount--; this._removeFromLightQueue(); if (scene._alternateLights._length > 0) { var alternateLight = scene._alternateLights.shift(); alternateLight._addToLightQueue(); alternateLight._isAlternate = false; scene._lightCount++; } } } _addToLightQueue() { } _removeFromLightQueue() { } _onActive() { super._onActive(); (this.lightmapBakedType !== LightSprite.LIGHTMAPBAKEDTYPE_BAKED) && (this._addToScene()); } _onInActive() { super._onInActive(); (this.lightmapBakedType !== LightSprite.LIGHTMAPBAKEDTYPE_BAKED) && (this._removeFromScene()); } _create() { return new LightSprite(); } get diffuseColor() { console.log("LightSprite: discard property,please use color property instead."); return this.color; } set diffuseColor(value) { console.log("LightSprite: discard property,please use color property instead."); this.color = value; } } LightSprite.LIGHTMAPBAKEDTYPE_REALTIME = 0; LightSprite.LIGHTMAPBAKEDTYPE_MIXED = 1; LightSprite.LIGHTMAPBAKEDTYPE_BAKED = 2; (function (ShadowCascadesMode) { ShadowCascadesMode[ShadowCascadesMode["NoCascades"] = 0] = "NoCascades"; ShadowCascadesMode[ShadowCascadesMode["TwoCascades"] = 1] = "TwoCascades"; ShadowCascadesMode[ShadowCascadesMode["FourCascades"] = 2] = "FourCascades"; })(exports.ShadowCascadesMode || (exports.ShadowCascadesMode = {})); var FrustumFace; (function (FrustumFace) { FrustumFace[FrustumFace["Near"] = 0] = "Near"; FrustumFace[FrustumFace["Far"] = 1] = "Far"; FrustumFace[FrustumFace["Left"] = 2] = "Left"; FrustumFace[FrustumFace["Right"] = 3] = "Right"; FrustumFace[FrustumFace["Bottom"] = 4] = "Bottom"; FrustumFace[FrustumFace["Top"] = 5] = "Top"; })(FrustumFace || (FrustumFace = {})); class ShadowUtils { static supportShadow() { return Laya.LayaGL.layaGPUInstance._isWebGL2 || Laya.SystemUtils.supportRenderTextureFormat(Laya.RenderTextureFormat.Depth); } static init() { if (Laya.LayaGL.layaGPUInstance._isWebGL2) ShadowUtils._shadowTextureFormat = Laya.RenderTextureFormat.ShadowMap; else ShadowUtils._shadowTextureFormat = Laya.RenderTextureFormat.Depth; } static getTemporaryShadowTexture(witdh, height, depthFormat) { var shadowMap = RenderTexture.createFromPool(witdh, height, ShadowUtils._shadowTextureFormat, depthFormat); shadowMap.filterMode = Laya.FilterMode.Bilinear; shadowMap.wrapModeU = Laya.WarpMode.Clamp; shadowMap.wrapModeV = Laya.WarpMode.Clamp; return shadowMap; } static getShadowBias(light, shadowProjectionMatrix, shadowResolution, out) { var frustumSize; if (light._lightType == exports.LightType.Directional) { frustumSize = 2.0 / shadowProjectionMatrix.elements[0]; } else if (light._lightType == exports.LightType.Spot) { frustumSize = Math.tan(light.spotAngle * 0.5 * MathUtils3D.Deg2Rad) * light.range; } else { console.warn("ShadowUtils:Only spot and directional shadow casters are supported now."); frustumSize = 0.0; } var texelSize = frustumSize / shadowResolution; var depthBias = -light._shadowDepthBias * texelSize; var normalBias = -light._shadowNormalBias * texelSize; if (light.shadowMode == exports.ShadowMode.SoftHigh) { const kernelRadius = 2.5; depthBias *= kernelRadius; normalBias *= kernelRadius; } out.setValue(depthBias, normalBias, 0.0, 0.0); } static getCameraFrustumPlanes(cameraViewProjectMatrix, frustumPlanes) { BoundFrustum.getPlanesFromMatrix(cameraViewProjectMatrix, frustumPlanes[FrustumFace.Near], frustumPlanes[FrustumFace.Far], frustumPlanes[FrustumFace.Left], frustumPlanes[FrustumFace.Right], frustumPlanes[FrustumFace.Top], frustumPlanes[FrustumFace.Bottom]); } static getFarWithRadius(radius, denominator) { return Math.sqrt(radius * radius / denominator); } static getCascadesSplitDistance(twoSplitRatio, fourSplitRatio, cameraNear, shadowFar, fov, aspectRatio, cascadesMode, out) { out[0] = cameraNear; var range = shadowFar - cameraNear; var tFov = Math.tan(fov * 0.5); var denominator = 1.0 + tFov * tFov * (aspectRatio * aspectRatio + 1.0); switch (cascadesMode) { case exports.ShadowCascadesMode.NoCascades: out[1] = ShadowUtils.getFarWithRadius(shadowFar, denominator); break; case exports.ShadowCascadesMode.TwoCascades: out[1] = ShadowUtils.getFarWithRadius(cameraNear + range * twoSplitRatio, denominator); out[2] = ShadowUtils.getFarWithRadius(shadowFar, denominator); break; case exports.ShadowCascadesMode.FourCascades: out[1] = ShadowUtils.getFarWithRadius(cameraNear + range * fourSplitRatio.x, denominator); out[2] = ShadowUtils.getFarWithRadius(cameraNear + range * fourSplitRatio.y, denominator); out[3] = ShadowUtils.getFarWithRadius(cameraNear + range * fourSplitRatio.z, denominator); out[4] = ShadowUtils.getFarWithRadius(shadowFar, denominator); break; } } static applySliceTransform(shadowSliceData, atlasWidth, atlasHeight, cascadeIndex, outShadowMatrices) { var sliceE = ShadowUtils._tempMatrix0.elements; var oneOverAtlasWidth = 1.0 / atlasWidth; var oneOverAtlasHeight = 1.0 / atlasHeight; sliceE[0] = shadowSliceData.resolution * oneOverAtlasWidth; sliceE[5] = shadowSliceData.resolution * oneOverAtlasHeight; sliceE[12] = shadowSliceData.offsetX * oneOverAtlasWidth; sliceE[13] = shadowSliceData.offsetY * oneOverAtlasHeight; sliceE[1] = sliceE[2] = sliceE[2] = sliceE[4] = sliceE[6] = sliceE[7] = sliceE[8] = sliceE[9] = sliceE[11] = sliceE[14] = 0; sliceE[10] = sliceE[15] = 1; var offset = cascadeIndex * 16; Utils3D._mulMatrixArray(sliceE, outShadowMatrices, offset, outShadowMatrices, offset); } static getDirectionLightShadowCullPlanes(cameraFrustumPlanes, cascadeIndex, splitDistance, cameraNear, direction, shadowSliceData) { var frustumCorners = ShadowUtils._frustumCorners; var backPlaneFaces = ShadowUtils._backPlaneFaces; var planeNeighbors = ShadowUtils._frustumPlaneNeighbors; var twoPlaneCorners = ShadowUtils._frustumTwoPlaneCorners; var edgePlanePoint2 = ShadowUtils._edgePlanePoint2; var out = shadowSliceData.cullPlanes; var near = cameraFrustumPlanes[FrustumFace.Near], far = cameraFrustumPlanes[FrustumFace.Far]; var left = cameraFrustumPlanes[FrustumFace.Left], right = cameraFrustumPlanes[FrustumFace.Right]; var bottom = cameraFrustumPlanes[FrustumFace.Bottom], top = cameraFrustumPlanes[FrustumFace.Top]; var splitNearDistance = splitDistance[cascadeIndex] - cameraNear; var splitNear = ShadowUtils._adjustNearPlane; var splitFar = ShadowUtils._adjustFarPlane; near.normal.cloneTo(splitNear.normal); far.normal.cloneTo(splitFar.normal); splitNear.distance = near.distance - splitNearDistance; splitFar.distance = Math.min(-near.distance + shadowSliceData.sphereCenterZ + shadowSliceData.splitBoundSphere.radius, far.distance); BoundFrustum.get3PlaneInterPoint(splitNear, bottom, right, frustumCorners[exports.FrustumCorner.nearBottomRight]); BoundFrustum.get3PlaneInterPoint(splitNear, top, right, frustumCorners[exports.FrustumCorner.nearTopRight]); BoundFrustum.get3PlaneInterPoint(splitNear, top, left, frustumCorners[exports.FrustumCorner.nearTopLeft]); BoundFrustum.get3PlaneInterPoint(splitNear, bottom, left, frustumCorners[exports.FrustumCorner.nearBottomLeft]); BoundFrustum.get3PlaneInterPoint(splitFar, bottom, right, frustumCorners[exports.FrustumCorner.FarBottomRight]); BoundFrustum.get3PlaneInterPoint(splitFar, top, right, frustumCorners[exports.FrustumCorner.FarTopRight]); BoundFrustum.get3PlaneInterPoint(splitFar, top, left, frustumCorners[exports.FrustumCorner.FarTopLeft]); BoundFrustum.get3PlaneInterPoint(splitFar, bottom, left, frustumCorners[exports.FrustumCorner.FarBottomLeft]); var backIndex = 0; for (var i = 0; i < 6; i++) { var plane; switch (i) { case FrustumFace.Near: plane = splitNear; break; case FrustumFace.Far: plane = splitFar; break; default: plane = cameraFrustumPlanes[i]; break; } if (Vector3.dot(plane.normal, direction) < 0.0) { plane.cloneTo(out[backIndex]); backPlaneFaces[backIndex] = i; backIndex++; } } var edgeIndex = backIndex; for (var i = 0; i < backIndex; i++) { var backFace = backPlaneFaces[i]; var neighborFaces = planeNeighbors[backFace]; for (var j = 0; j < 4; j++) { var neighborFace = neighborFaces[j]; var notBackFace = true; for (var k = 0; k < backIndex; k++) if (neighborFace == backPlaneFaces[k]) { notBackFace = false; break; } if (notBackFace) { var corners = twoPlaneCorners[backFace][neighborFace]; var point0 = frustumCorners[corners[0]]; var point1 = frustumCorners[corners[1]]; Vector3.add(point0, direction, edgePlanePoint2); Plane.createPlaneBy3P(point0, point1, edgePlanePoint2, out[edgeIndex++]); } } } shadowSliceData.cullPlaneCount = edgeIndex; } static getBoundSphereByFrustum(near, far, fov, aspectRatio, cameraPos, forward, outBoundSphere) { var centerZ; var radius; var k = Math.sqrt(1.0 + aspectRatio * aspectRatio) * Math.tan(fov / 2.0); var k2 = k * k; var farSNear = far - near; var farANear = far + near; if (k2 > farSNear / farANear) { centerZ = far; radius = far * k; } else { centerZ = 0.5 * farANear * (1 + k2); radius = 0.5 * Math.sqrt(farSNear * farSNear + 2.0 * (far * far + near * near) * k2 + farANear * farANear * k2 * k2); } var center = outBoundSphere.center; outBoundSphere.radius = radius; Vector3.scale(forward, centerZ, center); Vector3.add(cameraPos, center, center); return centerZ; } static getMaxTileResolutionInAtlas(atlasWidth, atlasHeight, tileCount) { var resolution = Math.min(atlasWidth, atlasHeight); var currentTileCount = Math.floor(atlasWidth / resolution) * Math.floor(atlasHeight / resolution); while (currentTileCount < tileCount) { resolution = Math.floor(resolution >> 1); currentTileCount = Math.floor(atlasWidth / resolution) * Math.floor(atlasHeight / resolution); } return resolution; } static getDirectionalLightMatrices(lightUp, lightSide, lightForward, cascadeIndex, nearPlane, shadowResolution, shadowSliceData, shadowMatrices) { var boundSphere = shadowSliceData.splitBoundSphere; var center = boundSphere.center; var radius = boundSphere.radius; var halfShadowResolution = shadowResolution / 2; var borderRadius = radius * halfShadowResolution / (halfShadowResolution - ShadowUtils.atlasBorderSize); var borderDiam = borderRadius * 2.0; var sizeUnit = shadowResolution / borderDiam; var radiusUnit = borderDiam / shadowResolution; var upLen = Math.ceil(Vector3.dot(center, lightUp) * sizeUnit) * radiusUnit; var sideLen = Math.ceil(Vector3.dot(center, lightSide) * sizeUnit) * radiusUnit; var forwardLen = Vector3.dot(center, lightForward); center.x = lightUp.x * upLen + lightSide.x * sideLen + lightForward.x * forwardLen; center.y = lightUp.y * upLen + lightSide.y * sideLen + lightForward.y * forwardLen; center.z = lightUp.z * upLen + lightSide.z * sideLen + lightForward.z * forwardLen; var origin = shadowSliceData.position; var viewMatrix = shadowSliceData.viewMatrix; var projectMatrix = shadowSliceData.projectionMatrix; var viewProjectMatrix = shadowSliceData.viewProjectMatrix; shadowSliceData.resolution = shadowResolution; shadowSliceData.offsetX = (cascadeIndex % 2) * shadowResolution; shadowSliceData.offsetY = Math.floor(cascadeIndex / 2) * shadowResolution; Vector3.scale(lightForward, radius + nearPlane, origin); Vector3.subtract(center, origin, origin); Matrix4x4.createLookAt(origin, center, lightUp, viewMatrix); Matrix4x4.createOrthoOffCenter(-borderRadius, borderRadius, -borderRadius, borderRadius, 0.0, radius * 2.0 + nearPlane, projectMatrix); Matrix4x4.multiply(projectMatrix, viewMatrix, viewProjectMatrix); Utils3D._mulMatrixArray(ShadowUtils._shadowMapScaleOffsetMatrix.elements, viewProjectMatrix.elements, 0, shadowMatrices, cascadeIndex * 16); } static getSpotLightShadowData(shadowSpotData, spotLight, resolution, shadowParams, shadowSpotMatrices, shadowMapSize) { var out = shadowSpotData.position = spotLight.transform.position; shadowSpotData.resolution = resolution; shadowMapSize.setValue(1.0 / resolution, 1.0 / resolution, resolution, resolution); shadowSpotData.offsetX = 0; shadowSpotData.offsetY = 0; var spotWorldMatrix = spotLight.transform.worldMatrix; var viewMatrix = shadowSpotData.viewMatrix; var projectMatrix = shadowSpotData.projectionMatrix; var viewProjectMatrix = shadowSpotData.viewProjectMatrix; var BoundFrustum = shadowSpotData.cameraCullInfo.boundFrustum; spotWorldMatrix.invert(viewMatrix); Matrix4x4.createPerspective(3.1416 * spotLight.spotAngle / 180.0, 1, 0.1, spotLight.range, projectMatrix); shadowParams.y = spotLight.shadowStrength; Matrix4x4.multiply(projectMatrix, viewMatrix, viewProjectMatrix); BoundFrustum.matrix = viewProjectMatrix; viewProjectMatrix.cloneTo(shadowSpotMatrices); shadowSpotData.cameraCullInfo.position = out; } static prepareShadowReceiverShaderValues(light, shadowMapWidth, shadowMapHeight, shadowSliceDatas, cascadeCount, shadowMapSize, shadowParams, shadowMatrices, splitBoundSpheres) { shadowMapSize.setValue(1.0 / shadowMapWidth, 1.0 / shadowMapHeight, shadowMapWidth, shadowMapHeight); shadowParams.setValue(light._shadowStrength, 0.0, 0.0, 0.0); if (cascadeCount > 1) { const matrixFloatCount = 16; for (var i = cascadeCount * matrixFloatCount, n = 4 * matrixFloatCount; i < n; i++) shadowMatrices[i] = 0.0; for (var i = 0; i < cascadeCount; i++) { var boundSphere = shadowSliceDatas[i].splitBoundSphere; var center = boundSphere.center; var radius = boundSphere.radius; var offset = i * 4; splitBoundSpheres[offset] = center.x; splitBoundSpheres[offset + 1] = center.y; splitBoundSpheres[offset + 2] = center.z; splitBoundSpheres[offset + 3] = radius * radius; } const sphereFloatCount = 4; for (var i = cascadeCount * sphereFloatCount, n = 4 * sphereFloatCount; i < n; i++) splitBoundSpheres[i] = 0.0; } } } ShadowUtils._tempMatrix0 = new Matrix4x4(); ShadowUtils._shadowMapScaleOffsetMatrix = new Matrix4x4(0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.5, 0.5, 0.0, 1.0); ShadowUtils._frustumCorners = [new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3()]; ShadowUtils._adjustNearPlane = new Plane(new Vector3()); ShadowUtils._adjustFarPlane = new Plane(new Vector3()); ShadowUtils._backPlaneFaces = new Array(5); ShadowUtils._edgePlanePoint2 = new Vector3(); ShadowUtils._frustumPlaneNeighbors = [ [FrustumFace.Left, FrustumFace.Right, FrustumFace.Top, FrustumFace.Bottom], [FrustumFace.Left, FrustumFace.Right, FrustumFace.Top, FrustumFace.Bottom], [FrustumFace.Near, FrustumFace.Far, FrustumFace.Top, FrustumFace.Bottom], [FrustumFace.Near, FrustumFace.Far, FrustumFace.Top, FrustumFace.Bottom], [FrustumFace.Near, FrustumFace.Far, FrustumFace.Left, FrustumFace.Right], [FrustumFace.Near, FrustumFace.Far, FrustumFace.Left, FrustumFace.Right] ]; ShadowUtils._frustumTwoPlaneCorners = [ [[exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.nearBottomLeft, exports.FrustumCorner.nearTopLeft], [exports.FrustumCorner.nearTopRight, exports.FrustumCorner.nearBottomRight], [exports.FrustumCorner.nearBottomRight, exports.FrustumCorner.nearBottomLeft], [exports.FrustumCorner.nearTopLeft, exports.FrustumCorner.nearTopRight]], [[exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.FarTopLeft, exports.FrustumCorner.FarBottomLeft], [exports.FrustumCorner.FarBottomRight, exports.FrustumCorner.FarTopRight], [exports.FrustumCorner.FarBottomLeft, exports.FrustumCorner.FarBottomRight], [exports.FrustumCorner.FarTopRight, exports.FrustumCorner.FarTopLeft]], [[exports.FrustumCorner.nearTopLeft, exports.FrustumCorner.nearBottomLeft], [exports.FrustumCorner.FarBottomLeft, exports.FrustumCorner.FarTopLeft], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.nearBottomLeft, exports.FrustumCorner.FarBottomLeft], [exports.FrustumCorner.FarTopLeft, exports.FrustumCorner.nearTopLeft]], [[exports.FrustumCorner.nearBottomRight, exports.FrustumCorner.nearTopRight], [exports.FrustumCorner.FarTopRight, exports.FrustumCorner.FarBottomRight], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.FarBottomRight, exports.FrustumCorner.nearBottomRight], [exports.FrustumCorner.nearTopRight, exports.FrustumCorner.FarTopRight]], [[exports.FrustumCorner.nearBottomLeft, exports.FrustumCorner.nearBottomRight], [exports.FrustumCorner.FarBottomRight, exports.FrustumCorner.FarBottomLeft], [exports.FrustumCorner.FarBottomLeft, exports.FrustumCorner.nearBottomLeft], [exports.FrustumCorner.nearBottomRight, exports.FrustumCorner.FarBottomRight], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown]], [[exports.FrustumCorner.nearTopRight, exports.FrustumCorner.nearTopLeft], [exports.FrustumCorner.FarTopLeft, exports.FrustumCorner.FarTopRight], [exports.FrustumCorner.nearTopLeft, exports.FrustumCorner.FarTopLeft], [exports.FrustumCorner.FarTopRight, exports.FrustumCorner.nearTopRight], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown], [exports.FrustumCorner.unknown, exports.FrustumCorner.unknown]] ]; ShadowUtils.atlasBorderSize = 4.0; (function (CameraClearFlags) { CameraClearFlags[CameraClearFlags["SolidColor"] = 0] = "SolidColor"; CameraClearFlags[CameraClearFlags["Sky"] = 1] = "Sky"; CameraClearFlags[CameraClearFlags["DepthOnly"] = 2] = "DepthOnly"; CameraClearFlags[CameraClearFlags["Nothing"] = 3] = "Nothing"; })(exports.CameraClearFlags || (exports.CameraClearFlags = {})); class Camera extends BaseCamera { constructor(aspectRatio = 0, nearPlane = 0.3, farPlane = 1000) { super(nearPlane, farPlane); this._updateViewMatrix = true; this._postProcess = null; this._enableHDR = false; this._viewportParams = new Vector4(); this._projectionParams = new Vector4(); this._offScreenRenderTexture = null; this._internalRenderTexture = null; this._postProcessCommandBuffers = []; this._clusterPlaneCacheFlag = new Vector2(-1, -1); this._screenOffsetScale = new Vector4(); this.enableRender = true; this.clearFlag = exports.CameraClearFlags.SolidColor; this._viewMatrix = new Matrix4x4(); this._projectionMatrix = new Matrix4x4(); this._projectionViewMatrix = new Matrix4x4(); this._viewport = new Viewport(0, 0, 0, 0); this._normalizedViewport = new Viewport(0, 0, 1, 1); this._aspectRatio = aspectRatio; this._boundFrustum = new BoundFrustum(new Matrix4x4()); if (Laya.Render.supportWebGLPlusCulling) this._boundFrustumBuffer = new Float32Array(24); this._calculateProjectionMatrix(); Laya.Laya.stage.on(Laya.Event.RESIZE, this, this._onScreenSizeChanged); this.transform.on(Laya.Event.TRANSFORM_CHANGED, this, this._onTransformChanged); } get aspectRatio() { if (this._aspectRatio === 0) { var vp = this.viewport; return vp.width / vp.height; } return this._aspectRatio; } set aspectRatio(value) { if (value < 0) throw new Error("Camera: the aspect ratio has to be a positive real number."); this._aspectRatio = value; this._calculateProjectionMatrix(); } get viewport() { if (this._offScreenRenderTexture) this._calculationViewport(this._normalizedViewport, this._offScreenRenderTexture.width, this._offScreenRenderTexture.height); else this._calculationViewport(this._normalizedViewport, RenderContext3D.clientWidth, RenderContext3D.clientHeight); return this._viewport; } set viewport(value) { var width; var height; if (this._offScreenRenderTexture) { width = this._offScreenRenderTexture.width; height = this._offScreenRenderTexture.height; } else { width = RenderContext3D.clientWidth; height = RenderContext3D.clientHeight; } this._normalizedViewport.x = value.x / width; this._normalizedViewport.y = value.y / height; this._normalizedViewport.width = value.width / width; this._normalizedViewport.height = value.height / height; this._calculationViewport(this._normalizedViewport, width, height); this._calculateProjectionMatrix(); } get normalizedViewport() { return this._normalizedViewport; } set normalizedViewport(value) { var width; var height; if (this._offScreenRenderTexture) { width = this._offScreenRenderTexture.width; height = this._offScreenRenderTexture.height; } else { width = RenderContext3D.clientWidth; height = RenderContext3D.clientHeight; } if (this._normalizedViewport !== value) value.cloneTo(this._normalizedViewport); this._calculationViewport(value, width, height); this._calculateProjectionMatrix(); } get viewMatrix() { if (this._updateViewMatrix) { var scale = this.transform.getWorldLossyScale(); var scaleX = scale.x; var scaleY = scale.y; var scaleZ = scale.z; var viewMatE = this._viewMatrix.elements; this.transform.worldMatrix.cloneTo(this._viewMatrix); viewMatE[0] /= scaleX; viewMatE[1] /= scaleX; viewMatE[2] /= scaleX; viewMatE[4] /= scaleY; viewMatE[5] /= scaleY; viewMatE[6] /= scaleY; viewMatE[8] /= scaleZ; viewMatE[9] /= scaleZ; viewMatE[10] /= scaleZ; this._viewMatrix.invert(this._viewMatrix); this._updateViewMatrix = false; } return this._viewMatrix; } get projectionMatrix() { return this._projectionMatrix; } set projectionMatrix(value) { this._projectionMatrix = value; this._useUserProjectionMatrix = true; } get projectionViewMatrix() { Matrix4x4.multiply(this.projectionMatrix, this.viewMatrix, this._projectionViewMatrix); return this._projectionViewMatrix; } get boundFrustum() { this._boundFrustum.matrix = this.projectionViewMatrix; if (Laya.Render.supportWebGLPlusCulling) { var near = this._boundFrustum.near; var far = this._boundFrustum.far; var left = this._boundFrustum.left; var right = this._boundFrustum.right; var top = this._boundFrustum.top; var bottom = this._boundFrustum.bottom; var nearNE = near.normal; var farNE = far.normal; var leftNE = left.normal; var rightNE = right.normal; var topNE = top.normal; var bottomNE = bottom.normal; var buffer = this._boundFrustumBuffer; buffer[0] = nearNE.x, buffer[1] = nearNE.y, buffer[2] = nearNE.z, buffer[3] = near.distance; buffer[4] = farNE.x, buffer[5] = farNE.y, buffer[6] = farNE.z, buffer[7] = far.distance; buffer[8] = leftNE.x, buffer[9] = leftNE.y, buffer[10] = leftNE.z, buffer[11] = left.distance; buffer[12] = rightNE.x, buffer[13] = rightNE.y, buffer[14] = rightNE.z, buffer[15] = right.distance; buffer[16] = topNE.x, buffer[17] = topNE.y, buffer[18] = topNE.z, buffer[19] = top.distance; buffer[20] = bottomNE.x, buffer[21] = bottomNE.y, buffer[22] = bottomNE.z, buffer[23] = bottom.distance; } return this._boundFrustum; } get renderTarget() { return this._offScreenRenderTexture; } set renderTarget(value) { var lastValue = this._offScreenRenderTexture; if (lastValue !== value) { (lastValue) && (lastValue._isCameraTarget = false); (value) && (value._isCameraTarget = true); this._offScreenRenderTexture = value; this._calculateProjectionMatrix(); } } get postProcess() { return this._postProcess; } set postProcess(value) { this._postProcess = value; var postProcessCommandBuffer = new CommandBuffer(); this.addCommandBuffer(Camera.CAMERAEVENT_POSTPROCESS, postProcessCommandBuffer); value._init(this, postProcessCommandBuffer); } get enableHDR() { return this._enableHDR; } set enableHDR(value) { if (value && !Laya.SystemUtils.supportRenderTextureFormat(Laya.RenderTextureFormat.R16G16B16A16)) { console.warn("Camera:can't enable HDR in this device."); return; } this._enableHDR = value; } _calculationViewport(normalizedViewport, width, height) { var lx = normalizedViewport.x * width; var ly = normalizedViewport.y * height; var rx = lx + Math.max(normalizedViewport.width * width, 0); var ry = ly + Math.max(normalizedViewport.height * height, 0); var ceilLeftX = Math.ceil(lx); var ceilLeftY = Math.ceil(ly); var floorRightX = Math.floor(rx); var floorRightY = Math.floor(ry); var pixelLeftX = ceilLeftX - lx >= 0.5 ? Math.floor(lx) : ceilLeftX; var pixelLeftY = ceilLeftY - ly >= 0.5 ? Math.floor(ly) : ceilLeftY; var pixelRightX = rx - floorRightX >= 0.5 ? Math.ceil(rx) : floorRightX; var pixelRightY = ry - floorRightY >= 0.5 ? Math.ceil(ry) : floorRightY; this._viewport.x = pixelLeftX; this._viewport.y = pixelLeftY; this._viewport.width = pixelRightX - pixelLeftX; this._viewport.height = pixelRightY - pixelLeftY; } _calculateProjectionMatrix() { if (!this._useUserProjectionMatrix) { if (this._orthographic) { var halfHeight = this.orthographicVerticalSize * 0.5; var halfWidth = halfHeight * this.aspectRatio; Matrix4x4.createOrthoOffCenter(-halfWidth, halfWidth, -halfHeight, halfHeight, this.nearPlane, this.farPlane, this._projectionMatrix); } else { Matrix4x4.createPerspective(3.1416 * this.fieldOfView / 180.0, this.aspectRatio, this.nearPlane, this.farPlane, this._projectionMatrix); } } } _isLayerVisible(layer) { return (Math.pow(2, layer) & this.cullingMask) != 0; } _onTransformChanged(flag) { flag &= Transform3D.TRANSFORM_WORLDMATRIX; (flag) && (this._updateViewMatrix = true); } _parse(data, spriteMap) { super._parse(data, spriteMap); var clearFlagData = data.clearFlag; (clearFlagData !== undefined) && (this.clearFlag = clearFlagData); var viewport = data.viewport; this.normalizedViewport = new Viewport(viewport[0], viewport[1], viewport[2], viewport[3]); var enableHDR = data.enableHDR; (enableHDR !== undefined) && (this.enableHDR = enableHDR); } _getCanvasWidth() { if (this._offScreenRenderTexture) return this._offScreenRenderTexture.width; else return RenderContext3D.clientWidth; } _getCanvasHeight() { if (this._offScreenRenderTexture) return this._offScreenRenderTexture.height; else return RenderContext3D.clientHeight; } _getRenderTexture() { return this._internalRenderTexture || this._offScreenRenderTexture; } _needInternalRenderTexture() { return this._postProcess || this._enableHDR ? true : false; } _applyPostProcessCommandBuffers() { for (var i = 0, n = this._postProcessCommandBuffers.length; i < n; i++) this._postProcessCommandBuffers[i]._apply(); } _getRenderTextureFormat() { if (this._enableHDR) return Laya.RenderTextureFormat.R16G16B16A16; else return Laya.RenderTextureFormat.R8G8B8; } _prepareCameraToRender() { super._prepareCameraToRender(); var vp = this.viewport; this._viewportParams.setValue(vp.x, vp.y, vp.width, vp.height); this._projectionParams.setValue(this._nearPlane, this._farPlane, RenderContext3D._instance.invertY ? -1 : 1, 0); this._shaderValues.setVector(BaseCamera.VIEWPORT, this._viewportParams); this._shaderValues.setVector(BaseCamera.PROJECTION_PARAMS, this._projectionParams); } _applyViewProject(context, viewMat, proMat) { var projectView; var shaderData = this._shaderValues; if (context.invertY) { Matrix4x4.multiply(BaseCamera._invertYScaleMatrix, proMat, BaseCamera._invertYProjectionMatrix); Matrix4x4.multiply(BaseCamera._invertYProjectionMatrix, viewMat, BaseCamera._invertYProjectionViewMatrix); proMat = BaseCamera._invertYProjectionMatrix; projectView = BaseCamera._invertYProjectionViewMatrix; } else { Matrix4x4.multiply(proMat, viewMat, this._projectionViewMatrix); projectView = this._projectionViewMatrix; } context.viewMatrix = viewMat; context.projectionMatrix = proMat; context.projectionViewMatrix = projectView; shaderData.setMatrix4x4(BaseCamera.VIEWMATRIX, viewMat); shaderData.setMatrix4x4(BaseCamera.PROJECTMATRIX, proMat); shaderData.setMatrix4x4(BaseCamera.VIEWPROJECTMATRIX, projectView); } _updateClusterPlaneXY() { var fieldOfView = this.fieldOfView; var aspectRatio = this.aspectRatio; if (this._clusterPlaneCacheFlag.x !== fieldOfView || this._clusterPlaneCacheFlag.y !== aspectRatio) { var clusterCount = Config3D._config.lightClusterCount; var xSlixe = clusterCount.x, ySlice = clusterCount.y; var xCount = xSlixe + 1, yCount = ySlice + 1; var xPlanes = this._clusterXPlanes, yPlanes = this._clusterYPlanes; if (!xPlanes) { xPlanes = this._clusterXPlanes = new Array(xCount); yPlanes = this._clusterYPlanes = new Array(yCount); for (var i = 0; i < xCount; i++) xPlanes[i] = new Vector3(); for (var i = 0; i < yCount; i++) yPlanes[i] = new Vector3(); } var halfY = Math.tan((this.fieldOfView / 2) * Math.PI / 180); var halfX = this.aspectRatio * halfY; var yLengthPerCluster = 2 * halfY / xSlixe; var xLengthPerCluster = 2 * halfX / ySlice; for (var i = 0; i < xCount; i++) { var angle = -halfX + xLengthPerCluster * i; var bigHypot = Math.sqrt(1 + angle * angle); var normX = 1 / bigHypot; var xPlane = xPlanes[i]; xPlane.setValue(normX, 0, -angle * normX); } for (var i = 0; i < yCount; i++) { var angle = halfY - yLengthPerCluster * i; var bigHypot = Math.sqrt(1 + angle * angle); var normY = -1 / bigHypot; var yPlane = yPlanes[i]; yPlane.setValue(0, normY, -angle * normY); } this._clusterPlaneCacheFlag.x = fieldOfView; this._clusterPlaneCacheFlag.y = aspectRatio; } } render(shader = null, replacementTag = null) { if (!this.activeInHierarchy) return; var viewport = this.viewport; var needInternalRT = this._needInternalRenderTexture(); var gl = Laya.LayaGL.instance; var context = RenderContext3D._instance; var scene = context.scene = this._scene; context.pipelineMode = "Forward"; if (needInternalRT) { this._internalRenderTexture = RenderTexture.createFromPool(viewport.width, viewport.height, this._getRenderTextureFormat(), Laya.RenderTextureDepthFormat.DEPTH_16); this._internalRenderTexture.filterMode = Laya.FilterMode.Bilinear; } else { this._internalRenderTexture = null; } var shadowCasterPass; var mainDirectLight = scene._mainDirectionLight; var needShadowCasterPass = mainDirectLight && mainDirectLight.shadowMode !== exports.ShadowMode.None && ShadowUtils.supportShadow(); if (needShadowCasterPass) { scene._shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT); scene._shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW); shadowCasterPass = ILaya3D.Scene3D._shadowCasterPass; shadowCasterPass.update(this, mainDirectLight, ILaya3D.ShadowLightType.DirectionLight); shadowCasterPass.render(context, scene, ILaya3D.ShadowLightType.DirectionLight); } else { scene._shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW); } var spotMainLight = scene._mainSpotLight; var spotneedShadowCasterPass = spotMainLight && spotMainLight.shadowMode !== exports.ShadowMode.None && ShadowUtils.supportShadow(); if (spotneedShadowCasterPass) { scene._shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW); scene._shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT); shadowCasterPass = ILaya3D.Scene3D._shadowCasterPass; shadowCasterPass.update(this, spotMainLight, ILaya3D.ShadowLightType.SpotLight); shadowCasterPass.render(context, scene, ILaya3D.ShadowLightType.SpotLight); } else { scene._shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT); } if (needShadowCasterPass) scene._shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW); if (spotneedShadowCasterPass) scene._shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT); context.camera = this; context.cameraShaderValue = this._shaderValues; Camera._updateMark++; scene._preRenderScript(); if (needInternalRT && !this._offScreenRenderTexture && (this.clearFlag == exports.CameraClearFlags.DepthOnly || this.clearFlag == exports.CameraClearFlags.Nothing)) { if (this._enableHDR) { var grabTexture = RenderTexture.createFromPool(viewport.width, viewport.height, Laya.RenderTextureFormat.R8G8B8, Laya.RenderTextureDepthFormat.DEPTH_16); grabTexture.filterMode = Laya.FilterMode.Bilinear; Laya.WebGLContext.bindTexture(gl, gl.TEXTURE_2D, grabTexture._getSource()); gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, viewport.x, RenderContext3D.clientHeight - (viewport.y + viewport.height), viewport.width, viewport.height); var blit = BlitScreenQuadCMD.create(grabTexture, this._internalRenderTexture); blit.run(); blit.recover(); RenderTexture.recoverToPool(grabTexture); } else { Laya.WebGLContext.bindTexture(gl, gl.TEXTURE_2D, this._internalRenderTexture._getSource()); gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, viewport.x, RenderContext3D.clientHeight - (viewport.y + viewport.height), viewport.width, viewport.height); } } var renderTex = this._getRenderTexture(); (renderTex) && (renderTex._start()); context.viewport = viewport; this._prepareCameraToRender(); var multiLighting = Config3D._config._multiLighting; (multiLighting) && (Cluster.instance.update(this, (this._scene))); this._applyViewProject(context, this.viewMatrix, this._projectionMatrix); scene._preCulling(context, this, shader, replacementTag); scene._clear(gl, context); scene._renderScene(context); scene._postRenderScript(); (renderTex) && (renderTex._end()); if (needInternalRT) { if (this._postProcess) { this._postProcess._render(); this._applyPostProcessCommandBuffers(); } else if (this._enableHDR) { var canvasWidth = this._getCanvasWidth(), canvasHeight = this._getCanvasHeight(); this._screenOffsetScale.setValue(viewport.x / canvasWidth, viewport.y / canvasHeight, viewport.width / canvasWidth, viewport.height / canvasHeight); var blit = BlitScreenQuadCMD.create(this._internalRenderTexture, this._offScreenRenderTexture ? this._offScreenRenderTexture : null, this._screenOffsetScale); blit.run(); blit.recover(); } RenderTexture.recoverToPool(this._internalRenderTexture); } if (needShadowCasterPass || spotneedShadowCasterPass) shadowCasterPass.cleanUp(); } viewportPointToRay(point, out) { Picker.calculateCursorRay(point, this.viewport, this._projectionMatrix, this.viewMatrix, null, out); } normalizedViewportPointToRay(point, out) { var finalPoint = Camera._tempVector20; var vp = this.viewport; finalPoint.x = point.x * vp.width; finalPoint.y = point.y * vp.height; Picker.calculateCursorRay(finalPoint, this.viewport, this._projectionMatrix, this.viewMatrix, null, out); } worldToViewportPoint(position, out) { Matrix4x4.multiply(this._projectionMatrix, this._viewMatrix, this._projectionViewMatrix); this.viewport.project(position, this._projectionViewMatrix, out); out.x = out.x / Laya.Laya.stage.clientScaleX; out.y = out.y / Laya.Laya.stage.clientScaleY; } worldToNormalizedViewportPoint(position, out) { Matrix4x4.multiply(this._projectionMatrix, this._viewMatrix, this._projectionViewMatrix); this.normalizedViewport.project(position, this._projectionViewMatrix, out); out.x = out.x / Laya.Laya.stage.clientScaleX; out.y = out.y / Laya.Laya.stage.clientScaleY; } convertScreenCoordToOrthographicCoord(source, out) { if (this._orthographic) { var clientWidth = RenderContext3D.clientWidth; var clientHeight = RenderContext3D.clientHeight; var ratioX = this.orthographicVerticalSize * this.aspectRatio / clientWidth; var ratioY = this.orthographicVerticalSize / clientHeight; out.x = (-clientWidth / 2 + source.x * Laya.Laya.stage.clientScaleX) * ratioX; out.y = (clientHeight / 2 - source.y * Laya.Laya.stage.clientScaleY) * ratioY; out.z = (this.nearPlane - this.farPlane) * (source.z + 1) / 2 - this.nearPlane; Vector3.transformCoordinate(out, this.transform.worldMatrix, out); return true; } else { return false; } } destroy(destroyChild = true) { this._offScreenRenderTexture = null; this.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onTransformChanged); super.destroy(destroyChild); } addCommandBuffer(event, commandBuffer) { switch (event) { case Camera.CAMERAEVENT_POSTPROCESS: this._postProcessCommandBuffers.push(commandBuffer); commandBuffer._camera = this; break; default: throw "Camera:unknown event."; } } removeCommandBuffer(event, commandBuffer) { switch (event) { case Camera.CAMERAEVENT_POSTPROCESS: var index = this._postProcessCommandBuffers.indexOf(commandBuffer); if (index !== -1) this._postProcessCommandBuffers.splice(index, 1); break; default: throw "Camera:unknown event."; } } removeCommandBuffers(event) { switch (event) { case Camera.CAMERAEVENT_POSTPROCESS: this._postProcessCommandBuffers.length = 0; break; default: throw "Camera:unknown event."; } } _create() { return new Camera(); } } Camera.CAMERAEVENT_POSTPROCESS = 0; Camera._tempVector20 = new Vector2(); Camera._updateMark = 0; class Input3D { constructor() { this._eventList = []; this._mouseTouch = new MouseTouch(); this._touchPool = []; this._touches = new SimpleSingletonList(); this._multiTouchEnabled = true; this._pushEventList = ((e) => { (e.cancelable) && (e.preventDefault()); this._eventList.push(e); }).bind(this); } __init__(canvas, scene) { this._scene = scene; canvas.oncontextmenu = function (e) { return false; }; } _onCanvasEvent(canvas) { canvas.addEventListener('mousedown', this._pushEventList); canvas.addEventListener('mouseup', this._pushEventList, true); canvas.addEventListener('mousemove', this._pushEventList, true); canvas.addEventListener("touchstart", this._pushEventList); canvas.addEventListener("touchend", this._pushEventList, true); canvas.addEventListener("touchmove", this._pushEventList, true); canvas.addEventListener("touchcancel", this._pushEventList, true); } _offCanvasEvent(canvas) { canvas.removeEventListener('mousedown', this._pushEventList); canvas.removeEventListener('mouseup', this._pushEventList, true); canvas.removeEventListener('mousemove', this._pushEventList, true); canvas.removeEventListener("touchstart", this._pushEventList); canvas.removeEventListener("touchend", this._pushEventList, true); canvas.removeEventListener("touchmove", this._pushEventList, true); canvas.removeEventListener("touchcancel", this._pushEventList, true); this._eventList.length = 0; this._touches.clear(); } touchCount() { return this._touches.length; } get multiTouchEnabled() { return this._multiTouchEnabled; } set multiTouchEnabled(value) { this._multiTouchEnabled = value; } _getTouch(touchID, type) { var touch = this._touchPool[touchID]; if ((type == 0 && touch && touch._getIndexInList() != -1)) return null; if (type == 1 && touch && (touch._getIndexInList() == -1)) return null; if (!touch) { touch = new Touch(); this._touchPool[touchID] = touch; touch._identifier = touchID; } return touch; } _mouseTouchDown() { var touch = this._mouseTouch; var sprite = touch.sprite; touch._pressedSprite = sprite; touch._pressedLoopCount = Laya.Stat.loopCount; if (sprite) { var scripts = sprite._scripts; if (scripts) { for (var i = 0, n = scripts.length; i < n; i++) scripts[i].onMouseDown(); } } } _mouseTouchUp() { var i, n; var touch = this._mouseTouch; var lastPressedSprite = touch._pressedSprite; touch._pressedSprite = null; touch._pressedLoopCount = -1; var sprite = touch.sprite; if (sprite) { if (sprite === lastPressedSprite) { var scripts = sprite._scripts; if (scripts) { for (i = 0, n = scripts.length; i < n; i++) scripts[i].onMouseClick(); } } } if (lastPressedSprite) { var lastScripts = lastPressedSprite._scripts; if (lastScripts) { for (i = 0, n = lastScripts.length; i < n; i++) lastScripts[i].onMouseUp(); } } } _mouseTouchRayCast(cameras) { var touchHitResult = Input3D._tempHitResult0; var touchPos = Input3D._tempVector20; var touchRay = Input3D._tempRay0; touchHitResult.succeeded = false; var x = this._mouseTouch.mousePositionX; var y = this._mouseTouch.mousePositionY; touchPos.x = x; touchPos.y = y; for (var i = cameras.length - 1; i >= 0; i--) { var camera = cameras[i]; var viewport = camera.viewport; if (touchPos.x >= viewport.x && touchPos.y >= viewport.y && touchPos.x <= viewport.width && touchPos.y <= viewport.height) { camera.viewportPointToRay(touchPos, touchRay); var sucess = this._scene._physicsSimulation.rayCast(touchRay, touchHitResult); if (sucess || (camera.clearFlag === exports.CameraClearFlags.SolidColor || camera.clearFlag === exports.CameraClearFlags.Sky)) break; } } var touch = this._mouseTouch; var lastSprite = touch.sprite; if (touchHitResult.succeeded) { var touchSprite = touchHitResult.collider.owner; touch.sprite = touchSprite; var scripts = touchSprite._scripts; if (lastSprite !== touchSprite) { if (scripts) { for (var j = 0, m = scripts.length; j < m; j++) scripts[j].onMouseEnter(); } } } else { touch.sprite = null; } if (lastSprite && (lastSprite !== touchSprite)) { var outScripts = lastSprite._scripts; if (outScripts) { for (j = 0, m = outScripts.length; j < m; j++) outScripts[j].onMouseOut(); } } } _changeTouches(changedTouches, flag) { var offsetX = 0, offsetY = 0; var lastCount = this._touches.length; for (var j = 0, m = changedTouches.length; j < m; j++) { var nativeTouch = changedTouches[j]; var identifier = nativeTouch.identifier; if (!this._multiTouchEnabled && identifier !== 0) continue; var touch = this._getTouch(identifier, flag); var pos = this._touchPool[identifier]._position; var mousePoint = Input3D._tempPoint; mousePoint.setTo(nativeTouch.pageX, nativeTouch.pageY); Laya.ILaya.stage._canvasTransform.invertTransformPoint(mousePoint); var posX = mousePoint.x; var posY = mousePoint.y; switch (flag) { case 0: if (!!touch) this._touches.add(touch); offsetX += posX; offsetY += posY; break; case 1: if (!!touch) this._touches.remove(touch); offsetX -= posX; offsetY -= posY; break; case 2: offsetX = posX - pos.x; offsetY = posY - pos.y; break; } pos.x = posX; pos.y = posY; } var touchCount = this._touches.length; if (touchCount === 0) { this._mouseTouch.mousePositionX = 0; this._mouseTouch.mousePositionY = 0; } else { this._mouseTouch.mousePositionX = (this._mouseTouch.mousePositionX * lastCount + offsetX) / touchCount; this._mouseTouch.mousePositionY = (this._mouseTouch.mousePositionY * lastCount + offsetY) / touchCount; } } _update() { var enablePhysics = Physics3D._enablePhysics && !PhysicsSimulation.disableSimulation; var i, n, j, m; n = this._eventList.length; var cameras = this._scene._cameraPool; if (n > 0) { var rayCast = false; for (i = 0; i < n; i++) { var e = this._eventList[i]; switch (e.type) { case "mousedown": (enablePhysics) && (this._mouseTouchDown()); break; case "mouseup": (enablePhysics) && (this._mouseTouchUp()); break; case "mousemove": var mousePoint = Input3D._tempPoint; mousePoint.setTo(e.pageX, e.pageY); Laya.ILaya.stage._canvasTransform.invertTransformPoint(mousePoint); this._mouseTouch.mousePositionX = mousePoint.x; this._mouseTouch.mousePositionY = mousePoint.y; (enablePhysics) && (rayCast = true); break; case "touchstart": var lastLength = this._touches.length; this._changeTouches(e.changedTouches, 0); if (enablePhysics) { (!Config3D._config.isUseCannonPhysicsEngine) && (this._mouseTouchRayCast(cameras)); (lastLength === 0) && (this._mouseTouchDown()); } break; case "touchend": case "touchcancel": this._changeTouches(e.changedTouches, 1); (enablePhysics && this._touches.length === 0) && (this._mouseTouchUp()); break; case "touchmove": this._changeTouches(e.changedTouches, 2); (enablePhysics) && (rayCast = true); break; default: throw "Input3D:unkonwn event type."; } } (rayCast) && (!Config3D._config.isUseCannonPhysicsEngine) && (this._mouseTouchRayCast(cameras)); this._eventList.length = 0; } if (enablePhysics) { var mouseTouch = this._mouseTouch; var pressedSprite = mouseTouch._pressedSprite; if (pressedSprite && (Laya.Stat.loopCount > mouseTouch._pressedLoopCount)) { var pressedScripts = pressedSprite._scripts; if (pressedScripts) { for (j = 0, m = pressedScripts.length; j < m; j++) pressedScripts[j].onMouseDrag(); } } var touchSprite = mouseTouch.sprite; if (touchSprite) { var scripts = touchSprite._scripts; if (scripts) { for (j = 0, m = scripts.length; j < m; j++) scripts[j].onMouseOver(); } } } } getTouch(index) { if (index < this._touches.length) { return this._touches.elements[index]; } else { return null; } } } Input3D._tempPoint = new Laya.Point(); Input3D._tempVector20 = new Vector2(); Input3D._tempRay0 = new Ray(new Vector3(), new Vector3()); Input3D._tempHitResult0 = new HitResult(); class PhysicsSettings { constructor() { this.flags = 0; this.maxSubSteps = 1; this.fixedTimeStep = 1.0 / 60.0; } } class VertexPositionTexture0 { constructor(position, textureCoordinate0) { this._position = position; this._textureCoordinate0 = textureCoordinate0; } static get vertexDeclaration() { return VertexPositionTexture0._vertexDeclaration; } static __init__() { VertexPositionTexture0._vertexDeclaration = new VertexDeclaration(20, [new VertexElement(0, VertexElementFormat.Vector3, VertexMesh.MESH_POSITION0), new VertexElement(12, VertexElementFormat.Vector2, VertexMesh.MESH_TEXTURECOORDINATE0)]); } get position() { return this._position; } get textureCoordinate0() { return this._textureCoordinate0; } get vertexDeclaration() { return VertexPositionTexture0._vertexDeclaration; } } class SkyDome extends SkyMesh { constructor(stacks = 48, slices = 48) { super(); var gl = Laya.LayaGL.instance; this._stacks = stacks; this._slices = slices; var vertexDeclaration = VertexPositionTexture0.vertexDeclaration; var vertexFloatCount = vertexDeclaration.vertexStride / 4; var numberVertices = (this._stacks + 1) * (this._slices + 1); var numberIndices = (3 * this._stacks * (this._slices + 1)) * 2; var vertices = new Float32Array(numberVertices * vertexFloatCount); var indices = new Uint16Array(numberIndices); var stackAngle = Math.PI / this._stacks; var sliceAngle = (Math.PI * 2.0) / this._slices; var vertexIndex = 0; var vertexCount = 0; var indexCount = 0; for (var stack = 0; stack < (this._stacks + 1); stack++) { var r = Math.sin(stack * stackAngle); var y = Math.cos(stack * stackAngle); for (var slice = 0; slice < (this._slices + 1); slice++) { var x = r * Math.sin(slice * sliceAngle); var z = r * Math.cos(slice * sliceAngle); vertices[vertexCount + 0] = x * SkyDome._radius; vertices[vertexCount + 1] = y * SkyDome._radius; vertices[vertexCount + 2] = z * SkyDome._radius; vertices[vertexCount + 3] = -(slice / this._slices) + 0.75; vertices[vertexCount + 4] = stack / this._stacks; vertexCount += vertexFloatCount; if (stack != (this._stacks - 1)) { indices[indexCount++] = vertexIndex + 1; indices[indexCount++] = vertexIndex; indices[indexCount++] = vertexIndex + (this._slices + 1); indices[indexCount++] = vertexIndex + (this._slices + 1); indices[indexCount++] = vertexIndex; indices[indexCount++] = vertexIndex + (this._slices); vertexIndex++; } } } this._vertexBuffer = new VertexBuffer3D(vertices.length * 4, gl.STATIC_DRAW, false); this._vertexBuffer.vertexDeclaration = vertexDeclaration; this._indexBuffer = new IndexBuffer3D(exports.IndexFormat.UInt16, indices.length, gl.STATIC_DRAW, false); this._vertexBuffer.setData(vertices.buffer); this._indexBuffer.setData(indices); var bufferState = new BufferState(); bufferState.bind(); bufferState.applyVertexBuffer(this._vertexBuffer); bufferState.applyIndexBuffer(this._indexBuffer); bufferState.unBind(); this._bufferState = bufferState; } static __init__() { SkyDome.instance = new SkyDome(); } get stacks() { return this._stacks; } get slices() { return this._slices; } _render(state) { var gl = Laya.LayaGL.instance; var indexCount = this._indexBuffer.indexCount; gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, 0); Laya.Stat.trianglesFaces += indexCount / 3; Laya.Stat.renderBatches++; } } SkyDome._radius = 1; (function (TextureCubeFace) { TextureCubeFace[TextureCubeFace["PositiveX"] = 0] = "PositiveX"; TextureCubeFace[TextureCubeFace["NegativeX"] = 1] = "NegativeX"; TextureCubeFace[TextureCubeFace["PositiveY"] = 2] = "PositiveY"; TextureCubeFace[TextureCubeFace["NegativeY"] = 3] = "NegativeY"; TextureCubeFace[TextureCubeFace["PositiveZ"] = 4] = "PositiveZ"; TextureCubeFace[TextureCubeFace["NegativeZ"] = 5] = "NegativeZ"; })(exports.TextureCubeFace || (exports.TextureCubeFace = {})); class TextureCube extends Laya.BaseTexture { constructor(size, format = Laya.TextureFormat.R8G8B8, mipmap = false) { super(format, mipmap); this._glTextureType = Laya.LayaGL.instance.TEXTURE_CUBE_MAP; this._width = size; this._height = size; var gl = Laya.LayaGL.instance; this._setWarpMode(gl.TEXTURE_WRAP_S, this._wrapModeU); this._setWarpMode(gl.TEXTURE_WRAP_T, this._wrapModeV); this._setFilterMode(this._filterMode); this._setAnisotropy(this._anisoLevel); if (this._mipmap) { this._mipmapCount = Math.ceil(Math.log2(size)) + 1; for (var i = 0; i < this._mipmapCount; i++) this._setPixels([], i, Math.max(size >> i, 1), Math.max(size >> i, 1)); this._setGPUMemory(size * size * 4 * (1 + 1 / 3) * 6); } else { this._mipmapCount = 1; this._setGPUMemory(size * size * 4 * 6); } } static get blackTexture() { return TextureCube._blackTexture; } static get grayTexture() { return TextureCube._grayTexture; } static __init__() { var blackTexture = new TextureCube(1, Laya.TextureFormat.R8G8B8, false); var grayTexture = new TextureCube(1, Laya.TextureFormat.R8G8B8, false); var pixels = new Uint8Array(3); pixels[0] = 0, pixels[1] = 0, pixels[2] = 0; blackTexture.setSixSidePixels([pixels, pixels, pixels, pixels, pixels, pixels]); blackTexture.lock = true; pixels[0] = 128, pixels[1] = 128, pixels[2] = 128; grayTexture.setSixSidePixels([pixels, pixels, pixels, pixels, pixels, pixels]); grayTexture.lock = true; TextureCube._grayTexture = grayTexture; TextureCube._blackTexture = blackTexture; } static _parse(data, propertyParams = null, constructParams = null) { var texture = constructParams ? new TextureCube(0, constructParams[0], constructParams[1]) : new TextureCube(0); texture.setSixSideImageSources(data); return texture; } static _parseBin(data, propertyParams = null, constructParams = null) { var texture = constructParams ? new TextureCube(0, constructParams[0], constructParams[1]) : new TextureCube(0); texture.setSixSideImageSources(data); return texture; } static load(url, complete) { Laya.ILaya.loader.create(url, complete, null, TextureCube.TEXTURECUBE); } get defaulteTexture() { return TextureCube.grayTexture; } _setPixels(pixels, miplevel, width, height) { var gl = Laya.LayaGL.instance; var glFormat = this._getGLFormat(); Laya.WebGLContext.bindTexture(gl, this._glTextureType, this._glTexture); if (this.format === Laya.TextureFormat.R8G8B8) { gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[0]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[1]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[2]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[3]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[4]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[5]); gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); } else { gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[0]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[1]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[2]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[3]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[4]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, miplevel, glFormat, width, height, 0, glFormat, gl.UNSIGNED_BYTE, pixels[5]); } } setSixSideImageSources(source, premultiplyAlpha = false) { var width; var height; for (var i = 0; i < 6; i++) { var img = source[i]; if (!img) { console.log("TextureCube: image Source can't be null."); return; } var nextWidth = img.width; var nextHeight = img.height; if (i > 0) { if (width !== nextWidth) { console.log("TextureCube: each side image's width and height must same."); return; } } width = nextWidth; height = nextHeight; if (width !== height) { console.log("TextureCube: each side image's width and height must same."); return; } } this._width = width; this._height = height; var gl = Laya.LayaGL.instance; Laya.WebGLContext.bindTexture(gl, this._glTextureType, this._glTexture); var glFormat = this._getGLFormat(); if (!Laya.Render.isConchApp) { (premultiplyAlpha) && (gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true)); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, glFormat, glFormat, gl.UNSIGNED_BYTE, source[0]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, glFormat, glFormat, gl.UNSIGNED_BYTE, source[1]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, glFormat, glFormat, gl.UNSIGNED_BYTE, source[2]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, glFormat, glFormat, gl.UNSIGNED_BYTE, source[3]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, glFormat, glFormat, gl.UNSIGNED_BYTE, source[4]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, glFormat, glFormat, gl.UNSIGNED_BYTE, source[5]); (premultiplyAlpha) && (gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false)); } else { if (premultiplyAlpha == true) { for (var j = 0; j < 6; j++) source[j].setPremultiplyAlpha(premultiplyAlpha); } gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source[0]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source[1]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source[2]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source[3]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source[4]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source[5]); } if (this._mipmap && this._isPot(width) && this._isPot(height)) { gl.generateMipmap(this._glTextureType); this._setGPUMemory(width * height * 4 * (1 + 1 / 3) * 6); } else { this._setGPUMemory(width * height * 4 * 6); } this._setWarpMode(gl.TEXTURE_WRAP_S, this._wrapModeU); this._setWarpMode(gl.TEXTURE_WRAP_T, this._wrapModeV); this._setFilterMode(this._filterMode); this._readyed = true; this._activeResource(); } setSixSidePixels(pixels, miplevel = 0) { if (!pixels) throw new Error("TextureCube:pixels can't be null."); var width = Math.max(this._width >> miplevel, 1); var height = Math.max(this._height >> miplevel, 1); var pixelsCount = width * height * this._getFormatByteCount(); if (pixels[0].length < pixelsCount) throw "TextureCube:pixels length should at least " + pixelsCount + "."; this._setPixels(pixels, miplevel, width, height); if (miplevel === 0) { var gl = Laya.LayaGL.instance; this._setWarpMode(gl.TEXTURE_WRAP_S, this._wrapModeU); this._setWarpMode(gl.TEXTURE_WRAP_T, this._wrapModeV); } this._readyed = true; this._activeResource(); } setImageSource(face, imageSource, miplevel = 0) { var width = this._width; var height = this._height; if (imageSource) { if (width !== imageSource.width || height !== imageSource.height) { console.log("TextureCube: imageSource's width and height must same."); return; } } var gl = Laya.LayaGL.instance; Laya.WebGLContext.bindTexture(gl, this._glTextureType, this._glTexture); var glFormat = this._getGLFormat(); switch (face) { case exports.TextureCubeFace.NegativeX: gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, miplevel, glFormat, glFormat, gl.UNSIGNED_BYTE, imageSource); break; case exports.TextureCubeFace.PositiveX: gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, miplevel, glFormat, glFormat, gl.UNSIGNED_BYTE, imageSource); break; case exports.TextureCubeFace.NegativeY: gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, miplevel, glFormat, glFormat, gl.UNSIGNED_BYTE, imageSource); break; case exports.TextureCubeFace.PositiveY: gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, miplevel, glFormat, glFormat, gl.UNSIGNED_BYTE, imageSource); break; case exports.TextureCubeFace.NegativeZ: gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, miplevel, glFormat, glFormat, gl.UNSIGNED_BYTE, imageSource); break; case exports.TextureCubeFace.PositiveZ: gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, miplevel, glFormat, glFormat, gl.UNSIGNED_BYTE, imageSource); break; } if (this._mipmap && this._isPot(width) && this._isPot(height)) { gl.generateMipmap(this._glTextureType); this._setGPUMemory(width * height * 4 * (1 + 1 / 3) * 6); } else { this._setGPUMemory(width * height * 4 * 6); } this._setWarpMode(gl.TEXTURE_WRAP_S, this._wrapModeU); this._setWarpMode(gl.TEXTURE_WRAP_T, this._wrapModeV); this._setFilterMode(this._filterMode); this._readyed = true; } } TextureCube.TEXTURECUBE = "TEXTURECUBE"; class LightQueue { constructor() { this._length = 0; this._elements = []; } add(light) { if (this._length === this._elements.length) this._elements.push(light); else this._elements[this._length] = light; this._length++; } remove(light) { var index = this._elements.indexOf(light); this._length--; if (index !== this._length) { var end = this._elements[this._length]; this._elements[index] = end; } } shift() { this._length--; return this._elements.shift(); } getBrightestLight() { var maxIntIndex; var maxIntensity = -1; var elements = this._elements; for (var i = 0; i < this._length; i++) { var intensity = elements[i]._intensity; if (maxIntensity < intensity) { maxIntensity = intensity; maxIntIndex = i; } } return maxIntIndex; } normalLightOrdering(brightestIndex) { var slements = this._elements; var firstLight = this._elements[0]; this._elements[0] = this._elements[brightestIndex]; this._elements[brightestIndex] = firstLight; } } class AlternateLightQueue extends LightQueue { remove(light) { var index = this._elements.indexOf(light); this._elements.splice(index, 1); this._length--; } } class PixelLineMaterial extends Material { constructor() { super(); this.setShaderName("LineShader"); this._shaderValues.setVector(PixelLineMaterial.COLOR, new Vector4(1.0, 1.0, 1.0, 1.0)); } static __initDefine__() { } get color() { return this._shaderValues.getVector(PixelLineMaterial.COLOR); } set color(value) { this._shaderValues.setVector(PixelLineMaterial.COLOR, value); } set depthWrite(value) { this._shaderValues.setBool(PixelLineMaterial.DEPTH_WRITE, value); } get depthWrite() { return this._shaderValues.getBool(PixelLineMaterial.DEPTH_WRITE); } set cull(value) { this._shaderValues.setInt(PixelLineMaterial.CULL, value); } get cull() { return this._shaderValues.getInt(PixelLineMaterial.CULL); } set blend(value) { this._shaderValues.setInt(PixelLineMaterial.BLEND, value); } get blend() { return this._shaderValues.getInt(PixelLineMaterial.BLEND); } set blendSrc(value) { this._shaderValues.setInt(PixelLineMaterial.BLEND_SRC, value); } get blendSrc() { return this._shaderValues.getInt(PixelLineMaterial.BLEND_SRC); } set blendDst(value) { this._shaderValues.setInt(PixelLineMaterial.BLEND_DST, value); } get blendDst() { return this._shaderValues.getInt(PixelLineMaterial.BLEND_DST); } set depthTest(value) { this._shaderValues.setInt(PixelLineMaterial.DEPTH_TEST, value); } get depthTest() { return this._shaderValues.getInt(PixelLineMaterial.DEPTH_TEST); } clone() { var dest = new PixelLineMaterial(); this.cloneTo(dest); return dest; } } PixelLineMaterial.COLOR = Shader3D.propertyNameToID("u_Color"); PixelLineMaterial.CULL = Shader3D.propertyNameToID("s_Cull"); PixelLineMaterial.BLEND = Shader3D.propertyNameToID("s_Blend"); PixelLineMaterial.BLEND_SRC = Shader3D.propertyNameToID("s_BlendSrc"); PixelLineMaterial.BLEND_DST = Shader3D.propertyNameToID("s_BlendDst"); PixelLineMaterial.DEPTH_TEST = Shader3D.propertyNameToID("s_DepthTest"); PixelLineMaterial.DEPTH_WRITE = Shader3D.propertyNameToID("s_DepthWrite"); class BoundBox { constructor(min, max) { this.min = min; this.max = max; } _rotateExtents(extents, rotation, out) { var extentsX = extents.x; var extentsY = extents.y; var extentsZ = extents.z; var matElements = rotation.elements; out.x = Math.abs(matElements[0] * extentsX) + Math.abs(matElements[4] * extentsY) + Math.abs(matElements[8] * extentsZ); out.y = Math.abs(matElements[1] * extentsX) + Math.abs(matElements[5] * extentsY) + Math.abs(matElements[9] * extentsZ); out.z = Math.abs(matElements[2] * extentsX) + Math.abs(matElements[6] * extentsY) + Math.abs(matElements[10] * extentsZ); } getCorners(corners) { corners.length = 8; var minX = this.min.x; var minY = this.min.y; var minZ = this.min.z; var maxX = this.max.x; var maxY = this.max.y; var maxZ = this.max.z; corners[0] = new Vector3(minX, maxY, maxZ); corners[1] = new Vector3(maxX, maxY, maxZ); corners[2] = new Vector3(maxX, minY, maxZ); corners[3] = new Vector3(minX, minY, maxZ); corners[4] = new Vector3(minX, maxY, minZ); corners[5] = new Vector3(maxX, maxY, minZ); corners[6] = new Vector3(maxX, minY, minZ); corners[7] = new Vector3(minX, minY, minZ); } getCenter(out) { Vector3.add(this.min, this.max, out); Vector3.scale(out, 0.5, out); } getExtent(out) { Vector3.subtract(this.max, this.min, out); Vector3.scale(out, 0.5, out); } setCenterAndExtent(center, extent) { Vector3.subtract(center, extent, this.min); Vector3.add(center, extent, this.max); } tranform(matrix, out) { var center = BoundBox._tempVector30; var extent = BoundBox._tempVector31; this.getCenter(center); this.getExtent(extent); Vector3.transformCoordinate(center, matrix, center); this._rotateExtents(extent, matrix, extent); out.setCenterAndExtent(center, extent); } toDefault() { this.min.toDefault(); this.max.toDefault(); } static createfromPoints(points, out) { if (points == null) throw new Error("points"); var min = out.min; var max = out.max; min.x = Number.MAX_VALUE; min.y = Number.MAX_VALUE; min.z = Number.MAX_VALUE; max.x = -Number.MAX_VALUE; max.y = -Number.MAX_VALUE; max.z = -Number.MAX_VALUE; for (var i = 0, n = points.length; i < n; ++i) { Vector3.min(min, points[i], min); Vector3.max(max, points[i], max); } } static merge(box1, box2, out) { Vector3.min(box1.min, box2.min, out.min); Vector3.max(box1.max, box2.max, out.max); } cloneTo(destObject) { var dest = destObject; this.min.cloneTo(dest.min); this.max.cloneTo(dest.max); } clone() { var dest = new BoundBox(new Vector3(), new Vector3()); this.cloneTo(dest); return dest; } } BoundBox._tempVector30 = new Vector3(); BoundBox._tempVector31 = new Vector3(); class Bounds { constructor(min, max) { this._updateFlag = 0; this._center = new Vector3(); this._extent = new Vector3(); this._boundBox = new BoundBox(new Vector3(), new Vector3()); min.cloneTo(this._boundBox.min); max.cloneTo(this._boundBox.max); this._setUpdateFlag(Bounds._UPDATE_CENTER | Bounds._UPDATE_EXTENT, true); } setMin(value) { var min = this._boundBox.min; if (value !== min) value.cloneTo(min); this._setUpdateFlag(Bounds._UPDATE_CENTER | Bounds._UPDATE_EXTENT, true); this._setUpdateFlag(Bounds._UPDATE_MIN, false); } getMin() { var min = this._boundBox.min; if (this._getUpdateFlag(Bounds._UPDATE_MIN)) { this._getMin(this.getCenter(), this.getExtent(), min); this._setUpdateFlag(Bounds._UPDATE_MIN, false); } return min; } setMax(value) { var max = this._boundBox.max; if (value !== max) value.cloneTo(max); this._setUpdateFlag(Bounds._UPDATE_CENTER | Bounds._UPDATE_EXTENT, true); this._setUpdateFlag(Bounds._UPDATE_MAX, false); } getMax() { var max = this._boundBox.max; if (this._getUpdateFlag(Bounds._UPDATE_MAX)) { this._getMax(this.getCenter(), this.getExtent(), max); this._setUpdateFlag(Bounds._UPDATE_MAX, false); } return max; } setCenter(value) { if (value !== this._center) value.cloneTo(this._center); this._setUpdateFlag(Bounds._UPDATE_MIN | Bounds._UPDATE_MAX, true); this._setUpdateFlag(Bounds._UPDATE_CENTER, false); } getCenter() { if (this._getUpdateFlag(Bounds._UPDATE_CENTER)) { this._getCenter(this.getMin(), this.getMax(), this._center); this._setUpdateFlag(Bounds._UPDATE_CENTER, false); } return this._center; } setExtent(value) { if (value !== this._extent) value.cloneTo(this._extent); this._setUpdateFlag(Bounds._UPDATE_MIN | Bounds._UPDATE_MAX, true); this._setUpdateFlag(Bounds._UPDATE_EXTENT, false); } getExtent() { if (this._getUpdateFlag(Bounds._UPDATE_EXTENT)) { this._getExtent(this.getMin(), this.getMax(), this._extent); this._setUpdateFlag(Bounds._UPDATE_EXTENT, false); } return this._extent; } _getUpdateFlag(type) { return (this._updateFlag & type) != 0; } _setUpdateFlag(type, value) { if (value) this._updateFlag |= type; else this._updateFlag &= ~type; } _getCenter(min, max, out) { Vector3.add(min, max, out); Vector3.scale(out, 0.5, out); } _getExtent(min, max, out) { Vector3.subtract(max, min, out); Vector3.scale(out, 0.5, out); } _getMin(center, extent, out) { Vector3.subtract(center, extent, out); } _getMax(center, extent, out) { Vector3.add(center, extent, out); } _rotateExtents(extents, rotation, out) { var extentsX = extents.x; var extentsY = extents.y; var extentsZ = extents.z; var matE = rotation.elements; out.x = Math.abs(matE[0] * extentsX) + Math.abs(matE[4] * extentsY) + Math.abs(matE[8] * extentsZ); out.y = Math.abs(matE[1] * extentsX) + Math.abs(matE[5] * extentsY) + Math.abs(matE[9] * extentsZ); out.z = Math.abs(matE[2] * extentsX) + Math.abs(matE[6] * extentsY) + Math.abs(matE[10] * extentsZ); } _tranform(matrix, out) { var outCen = out._center; var outExt = out._extent; Vector3.transformCoordinate(this.getCenter(), matrix, outCen); this._rotateExtents(this.getExtent(), matrix, outExt); out._boundBox.setCenterAndExtent(outCen, outExt); out._updateFlag = 0; } _getBoundBox() { if (this._updateFlag & Bounds._UPDATE_MIN) { var min = this._boundBox.min; this._getMin(this.getCenter(), this.getExtent(), min); this._setUpdateFlag(Bounds._UPDATE_MIN, false); } if (this._updateFlag & Bounds._UPDATE_MAX) { var max = this._boundBox.max; this._getMax(this.getCenter(), this.getExtent(), max); this._setUpdateFlag(Bounds._UPDATE_MAX, false); } return this._boundBox; } cloneTo(destObject) { var destBounds = destObject; this.getMin().cloneTo(destBounds._boundBox.min); this.getMax().cloneTo(destBounds._boundBox.max); this.getCenter().cloneTo(destBounds._center); this.getExtent().cloneTo(destBounds._extent); destBounds._updateFlag = 0; } clone() { var dest = new Bounds(new Vector3(), new Vector3()); this.cloneTo(dest); return dest; } } Bounds._UPDATE_MIN = 0x01; Bounds._UPDATE_MAX = 0x02; Bounds._UPDATE_CENTER = 0x04; Bounds._UPDATE_EXTENT = 0x08; class GeometryElement { constructor() { this._destroyed = false; } get destroyed() { return this._destroyed; } _getType() { throw "GeometryElement:must override it."; } _prepareRender(state) { return true; } _render(state) { throw "GeometryElement:must override it."; } destroy() { if (this._destroyed) return; this._destroyed = true; } } GeometryElement._typeCounter = 0; class PixelLineVertex { constructor() { } static get vertexDeclaration() { return PixelLineVertex._vertexDeclaration; } static __init__() { PixelLineVertex._vertexDeclaration = new VertexDeclaration(28, [new VertexElement(0, VertexElementFormat.Vector3, VertexMesh.MESH_POSITION0), new VertexElement(12, VertexElementFormat.Vector4, VertexMesh.MESH_COLOR0)]); } get vertexDeclaration() { return PixelLineVertex._vertexDeclaration; } } class PixelLineFilter extends GeometryElement { constructor(owner, maxLineCount) { super(); this._floatCountPerVertices = 7; this._minUpdate = Number.MAX_VALUE; this._maxUpdate = Number.MIN_VALUE; this._bufferState = new BufferState(); this._floatBound = new Float32Array(6); this._calculateBound = false; this._maxLineCount = 0; this._lineCount = 0; var pointCount = maxLineCount * 2; this._owner = owner; this._maxLineCount = maxLineCount; this._vertices = new Float32Array(pointCount * this._floatCountPerVertices); this._vertexBuffer = new VertexBuffer3D(PixelLineVertex.vertexDeclaration.vertexStride * pointCount, Laya.LayaGL.instance.STATIC_DRAW, false); this._vertexBuffer.vertexDeclaration = PixelLineVertex.vertexDeclaration; this._bufferState.bind(); this._bufferState.applyVertexBuffer(this._vertexBuffer); this._bufferState.unBind(); var min = PixelLineFilter._tempVector0; var max = PixelLineFilter._tempVector1; min.setValue(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); max.setValue(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); this._bounds = new Bounds(min, max); } _getType() { return PixelLineFilter._type; } _resizeLineData(maxCount) { var pointCount = maxCount * 2; var lastVertices = this._vertices; this._vertexBuffer.destroy(); this._maxLineCount = maxCount; var vertexCount = pointCount * this._floatCountPerVertices; this._vertices = new Float32Array(vertexCount); this._vertexBuffer = new VertexBuffer3D(PixelLineVertex.vertexDeclaration.vertexStride * pointCount, Laya.LayaGL.instance.STATIC_DRAW, false); this._vertexBuffer.vertexDeclaration = PixelLineVertex.vertexDeclaration; if (vertexCount < lastVertices.length) { this._vertices.set(new Float32Array(lastVertices.buffer, 0, vertexCount)); this._vertexBuffer.setData(this._vertices.buffer, 0, 0, vertexCount * 4); } else { this._vertices.set(lastVertices); this._vertexBuffer.setData(this._vertices.buffer, 0, 0, lastVertices.length * 4); } this._bufferState.bind(); this._bufferState.applyVertexBuffer(this._vertexBuffer); this._bufferState.unBind(); } _updateLineVertices(offset, startPosition, endPosition, startColor, endColor) { if (startPosition) { this._vertices[offset + 0] = startPosition.x; this._vertices[offset + 1] = startPosition.y; this._vertices[offset + 2] = startPosition.z; } if (startColor) { this._vertices[offset + 3] = startColor.r; this._vertices[offset + 4] = startColor.g; this._vertices[offset + 5] = startColor.b; this._vertices[offset + 6] = startColor.a; } if (endPosition) { this._vertices[offset + 7] = endPosition.x; this._vertices[offset + 8] = endPosition.y; this._vertices[offset + 9] = endPosition.z; } if (endColor) { this._vertices[offset + 10] = endColor.r; this._vertices[offset + 11] = endColor.g; this._vertices[offset + 12] = endColor.b; this._vertices[offset + 13] = endColor.a; } this._minUpdate = Math.min(this._minUpdate, offset); this._maxUpdate = Math.max(this._maxUpdate, offset + this._floatCountPerVertices * 2); var bounds = this._bounds; var floatBound = this._floatBound; var min = bounds.getMin(), max = bounds.getMax(); Vector3.min(min, startPosition, min); Vector3.min(min, endPosition, min); Vector3.max(max, startPosition, max); Vector3.max(max, endPosition, max); bounds.setMin(min); bounds.setMax(max); floatBound[0] = min.x, floatBound[1] = min.y, floatBound[2] = min.z; floatBound[3] = max.x, floatBound[4] = max.y, floatBound[5] = max.z; } _reCalculateBound() { if (this._calculateBound) { var vertices = this._vertices; var min = PixelLineFilter._tempVector0; var max = PixelLineFilter._tempVector1; min.setValue(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); max.setValue(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); for (var i = 0; i < this._lineCount * 2; ++i) { var offset = this._floatCountPerVertices * i; var x = vertices[offset + 0], y = vertices[offset + 1], z = vertices[offset + 2]; min.x = Math.min(x, min.x); min.y = Math.min(y, min.y); min.z = Math.min(z, min.z); max.x = Math.max(x, max.x); max.y = Math.max(y, max.y); max.z = Math.max(z, max.z); } this._bounds.setMin(min); this._bounds.setMax(max); var floatBound = this._floatBound; floatBound[0] = min.x, floatBound[1] = min.y, floatBound[2] = min.z; floatBound[3] = max.x, floatBound[4] = max.y, floatBound[5] = max.z; this._calculateBound = false; } } _removeLineData(index) { var floatCount = this._floatCountPerVertices * 2; var nextIndex = index + 1; var offset = index * floatCount; var vertices = this._vertices; var rightPartVertices = new Float32Array(vertices.buffer, nextIndex * floatCount * 4, (this._lineCount - nextIndex) * floatCount); vertices.set(rightPartVertices, offset); this._minUpdate = Math.min(this._minUpdate, offset); this._maxUpdate = Math.max(this._maxUpdate, offset + rightPartVertices.length); this._lineCount--; var floatBound = this._floatBound; var startX = vertices[offset], startY = vertices[offset + 1], startZ = vertices[offset + 2]; var endX = vertices[offset + 7], endY = vertices[offset + 8], endZ = vertices[offset + 9]; var minX = floatBound[0], minY = floatBound[1], minZ = floatBound[2]; var maxX = floatBound[3], maxY = floatBound[4], maxZ = floatBound[5]; if ((startX === minX) || (startX === maxX) || (startY === minY) || (startY === maxY) || (startZ === minZ) || (startZ === maxZ) || (endX === minX) || (endX === maxX) || (endY === minY) || (endY === maxY) || (endZ === minZ) || (endZ === maxZ)) this._calculateBound = true; } _updateLineData(index, startPosition, endPosition, startColor, endColor) { var floatCount = this._floatCountPerVertices * 2; this._updateLineVertices(index * floatCount, startPosition, endPosition, startColor, endColor); } _updateLineDatas(index, data) { var floatCount = this._floatCountPerVertices * 2; var count = data.length; for (var i = 0; i < count; i++) { var line = data[i]; this._updateLineVertices((index + i) * floatCount, line.startPosition, line.endPosition, line.startColor, line.endColor); } } _getLineData(index, out) { var startPosition = out.startPosition; var startColor = out.startColor; var endPosition = out.endPosition; var endColor = out.endColor; var vertices = this._vertices; var offset = index * this._floatCountPerVertices * 2; startPosition.x = vertices[offset + 0]; startPosition.y = vertices[offset + 1]; startPosition.z = vertices[offset + 2]; startColor.r = vertices[offset + 3]; startColor.g = vertices[offset + 4]; startColor.b = vertices[offset + 5]; startColor.a = vertices[offset + 6]; endPosition.x = vertices[offset + 7]; endPosition.y = vertices[offset + 8]; endPosition.z = vertices[offset + 9]; endColor.r = vertices[offset + 10]; endColor.g = vertices[offset + 11]; endColor.b = vertices[offset + 12]; endColor.a = vertices[offset + 13]; } _prepareRender(state) { return true; } _render(state) { if (this._minUpdate !== Number.MAX_VALUE && this._maxUpdate !== Number.MIN_VALUE) { this._vertexBuffer.setData(this._vertices.buffer, this._minUpdate * 4, this._minUpdate * 4, (this._maxUpdate - this._minUpdate) * 4); this._minUpdate = Number.MAX_VALUE; this._maxUpdate = Number.MIN_VALUE; } if (this._lineCount > 0) { this._bufferState.bind(); var gl = Laya.LayaGL.instance; gl.drawArrays(gl.LINES, 0, this._lineCount * 2); Laya.Stat.renderBatches++; } } destroy() { if (this._destroyed) return; super.destroy(); this._bufferState.destroy(); this._vertexBuffer.destroy(); this._bufferState = null; this._vertexBuffer = null; this._vertices = null; } } PixelLineFilter._tempVector0 = new Vector3(); PixelLineFilter._tempVector1 = new Vector3(); PixelLineFilter._type = GeometryElement._typeCounter++; class RenderableSprite3D extends Sprite3D { constructor(name) { super(name); } static __init__() { RenderableSprite3D.SHADERDEFINE_RECEIVE_SHADOW = Shader3D.getDefineByName("RECEIVESHADOW"); RenderableSprite3D.SAHDERDEFINE_LIGHTMAP = Shader3D.getDefineByName("LIGHTMAP"); RenderableSprite3D.SHADERDEFINE_LIGHTMAP_DIRECTIONAL = Shader3D.getDefineByName("LIGHTMAP_DIRECTIONAL"); } _onInActive() { super._onInActive(); this._scene._removeRenderObject(this._render); } _onActive() { super._onActive(); this._scene._addRenderObject(this._render); } _onActiveInScene() { super._onActiveInScene(); if (ILaya3D.Laya3D._editerEnvironment) { var scene = this._scene; var pickColor = new Vector4(); scene._allotPickColorByID(this.id, pickColor); scene._pickIdToSprite[this.id] = this; this._render._shaderValues.setVector(RenderableSprite3D.PICKCOLOR, pickColor); } } _addToInitStaticBatchManager() { } _setBelongScene(scene) { super._setBelongScene(scene); this._render._setBelongScene(scene); } _setUnBelongScene() { this._render._shaderValues.removeDefine(RenderableSprite3D.SAHDERDEFINE_LIGHTMAP); super._setUnBelongScene(); } _changeHierarchyAnimator(animator) { if (this._hierarchyAnimator) { var renderableSprites = this._hierarchyAnimator._renderableSprites; renderableSprites.splice(renderableSprites.indexOf(this), 1); } if (animator) animator._renderableSprites.push(this); super._changeHierarchyAnimator(animator); } destroy(destroyChild = true) { super.destroy(destroyChild); this._render._destroy(); this._render = null; } _create() { return new RenderableSprite3D(this.name); } } RenderableSprite3D.LIGHTMAPSCALEOFFSET = Shader3D.propertyNameToID("u_LightmapScaleOffset"); RenderableSprite3D.LIGHTMAP = Shader3D.propertyNameToID("u_LightMap"); RenderableSprite3D.LIGHTMAP_DIRECTION = Shader3D.propertyNameToID("u_LightMapDirection"); RenderableSprite3D.PICKCOLOR = Shader3D.propertyNameToID("u_PickColor"); class BatchMark { constructor() { this.updateMark = -1; this.indexInList = -1; this.batched = false; } } class SubMeshInstanceBatch extends GeometryElement { constructor() { super(); this.maxInstanceCount = 1024; this.instanceWorldMatrixData = new Float32Array(this.maxInstanceCount * 16); this.instanceMVPMatrixData = new Float32Array(this.maxInstanceCount * 16); var gl = Laya.LayaGL.instance; this.instanceWorldMatrixBuffer = new VertexBuffer3D(this.instanceWorldMatrixData.length * 4, gl.DYNAMIC_DRAW); this.instanceMVPMatrixBuffer = new VertexBuffer3D(this.instanceMVPMatrixData.length * 4, gl.DYNAMIC_DRAW); this.instanceWorldMatrixBuffer.vertexDeclaration = VertexMesh.instanceWorldMatrixDeclaration; this.instanceMVPMatrixBuffer.vertexDeclaration = VertexMesh.instanceMVPMatrixDeclaration; } static __init__() { SubMeshInstanceBatch.instance = new SubMeshInstanceBatch(); } _render(state) { var gl = Laya.LayaGL.instance; var element = state.renderElement; var subMesh = element.instanceSubMesh; var count = element.instanceBatchElementList.length; var indexCount = subMesh._indexCount; subMesh._mesh._instanceBufferState.bind(); Laya.LayaGL.layaGPUInstance.drawElementsInstanced(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, subMesh._indexStart * 2, count); Laya.Stat.renderBatches++; Laya.Stat.savedRenderBatches += count - 1; Laya.Stat.trianglesFaces += indexCount * count / 3; } } class RenderElement { constructor() { this.renderSubShader = null; this.renderType = RenderElement.RENDERTYPE_NORMAL; } getInvertFront() { return this._transform._isFrontFaceInvert; } setTransform(transform) { this._transform = transform; } setGeometry(geometry) { this._geometry = geometry; } addToOpaqueRenderQueue(context, queue) { queue.elements.add(this); } addToTransparentRenderQueue(context, queue) { queue.elements.add(this); queue.lastTransparentBatched = false; queue.lastTransparentRenderElement = this; } _update(scene, context, customShader, replacementTag) { if (this.material) { var subShader = this.material._shader.getSubShaderAt(0); this.renderSubShader = null; if (customShader) { if (replacementTag) { var oriTag = subShader.getFlag(replacementTag); if (oriTag) { var customSubShaders = customShader._subShaders; for (var k = 0, p = customSubShaders.length; k < p; k++) { var customSubShader = customSubShaders[k]; if (oriTag === customSubShader.getFlag(replacementTag)) { this.renderSubShader = customSubShader; break; } } if (!this.renderSubShader) return; } else { return; } } else { this.renderSubShader = customShader.getSubShaderAt(0); } } else { this.renderSubShader = subShader; } var renderQueue = scene._getRenderQueue(this.material.renderQueue); if (renderQueue.isTransparent) this.addToTransparentRenderQueue(context, renderQueue); else this.addToOpaqueRenderQueue(context, renderQueue); } } _render(context) { var forceInvertFace = context.invertY; var lastStateMaterial, lastStateShaderInstance, lastStateRender; var updateMark = Camera._updateMark; var scene = context.scene; var cameraShaderValue = context.cameraShaderValue; var transform = this._transform; var geometry = this._geometry; context.renderElement = this; var updateRender = updateMark !== this.render._updateMark || this.renderType !== this.render._updateRenderType; if (updateRender) { this.render._renderUpdate(context, transform); this.render._renderUpdateWithCamera(context, transform); this.render._updateMark = updateMark; this.render._updateRenderType = this.renderType; } else { if (this.renderType == RenderElement.RENDERTYPE_INSTANCEBATCH) { this.render._renderUpdate(context, transform); this.render._renderUpdateWithCamera(context, transform); } } var currentPipelineMode = context.pipelineMode; if (geometry._prepareRender(context)) { var passes = this.renderSubShader._passes; for (var j = 0, m = passes.length; j < m; j++) { var pass = passes[j]; if (pass._pipelineMode !== currentPipelineMode) continue; var comDef = RenderElement._compileDefine; scene._shaderValues._defineDatas.cloneTo(comDef); comDef.addDefineDatas(this.render._shaderValues._defineDatas); comDef.addDefineDatas(this.material._shaderValues._defineDatas); var shaderIns = context.shader = pass.withCompile(comDef); var switchShader = shaderIns.bind(); var switchUpdateMark = (updateMark !== shaderIns._uploadMark); var uploadScene = (shaderIns._uploadScene !== scene) || switchUpdateMark; if (uploadScene || switchShader) { shaderIns.uploadUniforms(shaderIns._sceneUniformParamsMap, scene._shaderValues, uploadScene); shaderIns._uploadScene = scene; } var uploadSprite3D = (shaderIns._uploadRender !== this.render || shaderIns._uploadRenderType !== this.renderType) || switchUpdateMark; if (uploadSprite3D || switchShader) { shaderIns.uploadUniforms(shaderIns._spriteUniformParamsMap, this.render._shaderValues, uploadSprite3D); shaderIns._uploadRender = this.render; shaderIns._uploadRenderType = this.renderType; } var uploadCamera = shaderIns._uploadCameraShaderValue !== cameraShaderValue || switchUpdateMark; if (uploadCamera || switchShader) { shaderIns.uploadUniforms(shaderIns._cameraUniformParamsMap, cameraShaderValue, uploadCamera); shaderIns._uploadCameraShaderValue = cameraShaderValue; } var uploadMaterial = (shaderIns._uploadMaterial !== this.material) || switchUpdateMark; if (uploadMaterial || switchShader) { shaderIns.uploadUniforms(shaderIns._materialUniformParamsMap, this.material._shaderValues, uploadMaterial); shaderIns._uploadMaterial = this.material; } var matValues = this.material._shaderValues; if (lastStateMaterial !== this.material || lastStateShaderInstance !== shaderIns) { shaderIns.uploadRenderStateBlendDepth(matValues); shaderIns.uploadRenderStateFrontFace(matValues, forceInvertFace, this.getInvertFront()); lastStateMaterial = this.material; lastStateShaderInstance = shaderIns; lastStateRender = this.render; } else { if (lastStateRender !== this.render) { shaderIns.uploadRenderStateFrontFace(matValues, forceInvertFace, this.getInvertFront()); lastStateRender = this.render; } } geometry._render(context); shaderIns._uploadMark = updateMark; } } if (this.renderType !== RenderElement.RENDERTYPE_NORMAL) this.render._revertBatchRenderUpdate(context); } destroy() { this._transform = null; this._geometry = null; this.material = null; this.render = null; } } RenderElement.RENDERTYPE_NORMAL = 0; RenderElement.RENDERTYPE_STATICBATCH = 1; RenderElement.RENDERTYPE_INSTANCEBATCH = 2; RenderElement.RENDERTYPE_VERTEXBATCH = 3; RenderElement._compileDefine = new DefineDatas(); class SubMeshRenderElement extends RenderElement { constructor() { super(); this._dynamicWorldPositionNormalNeedUpdate = true; } _onWorldMatrixChanged() { this._dynamicWorldPositionNormalNeedUpdate = true; } _computeWorldPositionsAndNormals(positionOffset, normalOffset, multiSubMesh, vertexCount) { if (this._dynamicWorldPositionNormalNeedUpdate) { var subMesh = this._geometry; var vertexBuffer = subMesh._vertexBuffer; var vertexFloatCount = vertexBuffer.vertexDeclaration.vertexStride / 4; var oriVertexes = vertexBuffer.getFloat32Data(); var worldMat = this._transform.worldMatrix; var rotation = this._transform.rotation; var indices = subMesh._indices; for (var i = 0; i < vertexCount; i++) { var index = multiSubMesh ? indices[i] : i; var oriOffset = index * vertexFloatCount; var bakeOffset = i * 3; Utils3D.transformVector3ArrayToVector3ArrayCoordinate(oriVertexes, oriOffset + positionOffset, worldMat, this._dynamicWorldPositions, bakeOffset); (normalOffset !== -1) && (Utils3D.transformVector3ArrayByQuat(oriVertexes, oriOffset + normalOffset, rotation, this._dynamicWorldNormals, bakeOffset)); } this._dynamicWorldPositionNormalNeedUpdate = false; } } setTransform(transform) { if (this._transform !== transform) { (this._transform) && (this._transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatrixChanged)); (transform) && (transform.on(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatrixChanged)); this._dynamicWorldPositionNormalNeedUpdate = true; this._transform = transform; } } setGeometry(geometry) { if (this._geometry !== geometry) { var subMesh = geometry; var mesh = subMesh._mesh; if (mesh) { var multiSubMesh = mesh._subMeshes.length > 1; var dynBatVerCount = multiSubMesh ? subMesh._indexCount : mesh._vertexCount; if (dynBatVerCount <= ILaya3D.SubMeshDynamicBatch.maxAllowVertexCount) { var length = dynBatVerCount * 3; this._dynamicVertexBatch = true; this._dynamicWorldPositions = new Float32Array(length); this._dynamicWorldNormals = new Float32Array(length); this._dynamicVertexCount = dynBatVerCount; this._dynamicMultiSubMesh = multiSubMesh; } else { this._dynamicVertexBatch = false; } } this._geometry = geometry; } } addToOpaqueRenderQueue(context, queue) { var subMeshStaticBatch = this.staticBatch; var queueElements = queue.elements; var elements = queueElements.elements; if (subMeshStaticBatch) { var staManager = ILaya3D.MeshRenderStaticBatchManager.instance; var staBatchMarks = staManager.getBatchOpaquaMark(this.render.lightmapIndex + 1, this.render.receiveShadow, this.material.id, subMeshStaticBatch._batchID); if (staManager._updateCountMark === staBatchMarks.updateMark) { var staBatchIndex = staBatchMarks.indexInList; if (staBatchMarks.batched) { elements[staBatchIndex].staticBatchElementList.add(this); } else { var staOriElement = elements[staBatchIndex]; var staOriRender = staOriElement.render; var staBatchElement = staManager._getBatchRenderElementFromPool(); staBatchElement.renderType = RenderElement.RENDERTYPE_STATICBATCH; staBatchElement.setGeometry(subMeshStaticBatch); staBatchElement.material = staOriElement.material; var staRootOwner = subMeshStaticBatch.batchOwner; var staBatchTransform = staRootOwner ? staRootOwner._transform : null; staBatchElement.setTransform(staBatchTransform); staBatchElement.render = staOriRender; staBatchElement.renderSubShader = staOriElement.renderSubShader; var staBatchList = staBatchElement.staticBatchElementList; staBatchList.length = 0; staBatchList.add(staOriElement); staBatchList.add(this); elements[staBatchIndex] = staBatchElement; staBatchMarks.batched = true; } } else { staBatchMarks.updateMark = staManager._updateCountMark; staBatchMarks.indexInList = queueElements.length; staBatchMarks.batched = false; queueElements.add(this); } } else if (this.renderSubShader._owner._enableInstancing && Laya.LayaGL.layaGPUInstance.supportInstance() && this.render.lightmapIndex < 0) { var subMesh = this._geometry; var insManager = ILaya3D.MeshRenderDynamicBatchManager.instance; var insBatchMarks = insManager.getInstanceBatchOpaquaMark(this.render.receiveShadow, this.material.id, subMesh._id, this._transform._isFrontFaceInvert); if (insManager._updateCountMark === insBatchMarks.updateMark) { var insBatchIndex = insBatchMarks.indexInList; if (insBatchMarks.batched) { var instanceBatchElementList = elements[insBatchIndex].instanceBatchElementList; if (instanceBatchElementList.length === SubMeshInstanceBatch.instance.maxInstanceCount) { insBatchMarks.updateMark = insManager._updateCountMark; insBatchMarks.indexInList = queueElements.length; insBatchMarks.batched = false; queueElements.add(this); } else { instanceBatchElementList.add(this); } } else { var insOriElement = elements[insBatchIndex]; var insOriRender = insOriElement.render; var insBatchElement = insManager._getBatchRenderElementFromPool(); insBatchElement.renderType = RenderElement.RENDERTYPE_INSTANCEBATCH; insBatchElement.setGeometry(SubMeshInstanceBatch.instance); insBatchElement.material = insOriElement.material; insBatchElement.setTransform(null); insBatchElement.render = insOriRender; insBatchElement.instanceSubMesh = subMesh; insBatchElement.renderSubShader = insOriElement.renderSubShader; var insBatchList = insBatchElement.instanceBatchElementList; insBatchList.length = 0; insBatchList.add(insOriElement); insBatchList.add(this); elements[insBatchIndex] = insBatchElement; insBatchMarks.batched = true; } } else { insBatchMarks.updateMark = insManager._updateCountMark; insBatchMarks.indexInList = queueElements.length; insBatchMarks.batched = false; queueElements.add(this); } } else if (this._dynamicVertexBatch) { var verDec = this._geometry._vertexBuffer.vertexDeclaration; var dynManager = ILaya3D.MeshRenderDynamicBatchManager.instance; var dynBatchMarks = dynManager.getVertexBatchOpaquaMark(this.render.lightmapIndex + 1, this.render.receiveShadow, this.material.id, verDec.id); if (dynManager._updateCountMark === dynBatchMarks.updateMark) { var dynBatchIndex = dynBatchMarks.indexInList; if (dynBatchMarks.batched) { elements[dynBatchIndex].vertexBatchElementList.add(this); } else { var dynOriElement = elements[dynBatchIndex]; var dynOriRender = dynOriElement.render; var dynBatchElement = dynManager._getBatchRenderElementFromPool(); dynBatchElement.renderType = RenderElement.RENDERTYPE_VERTEXBATCH; dynBatchElement.setGeometry(ILaya3D.SubMeshDynamicBatch.instance); dynBatchElement.material = dynOriElement.material; dynBatchElement.setTransform(null); dynBatchElement.render = dynOriRender; dynBatchElement.vertexBatchVertexDeclaration = verDec; dynBatchElement.renderSubShader = dynOriElement.renderSubShader; var dynBatchList = dynBatchElement.vertexBatchElementList; dynBatchList.length = 0; dynBatchList.add(dynOriElement); dynBatchList.add(this); elements[dynBatchIndex] = dynBatchElement; dynBatchMarks.batched = true; } } else { dynBatchMarks.updateMark = dynManager._updateCountMark; dynBatchMarks.indexInList = queueElements.length; dynBatchMarks.batched = false; queueElements.add(this); } } else { queueElements.add(this); } } addToTransparentRenderQueue(context, queue) { var subMeshStaticBatch = this.staticBatch; var queueElements = queue.elements; var elements = queueElements.elements; if (subMeshStaticBatch) { var staManager = ILaya3D.MeshRenderStaticBatchManager.instance; var staLastElement = queue.lastTransparentRenderElement; if (staLastElement) { var staLastRender = staLastElement.render; if (staLastElement._geometry._getType() !== this._geometry._getType() || staLastElement.staticBatch !== subMeshStaticBatch || staLastElement.material !== this.material || staLastRender.receiveShadow !== this.render.receiveShadow || staLastRender.lightmapIndex !== this.render.lightmapIndex) { queueElements.add(this); queue.lastTransparentBatched = false; } else { if (queue.lastTransparentBatched) { elements[queueElements.length - 1].staticBatchElementList.add((this)); } else { var staBatchElement = staManager._getBatchRenderElementFromPool(); staBatchElement.renderType = RenderElement.RENDERTYPE_STATICBATCH; staBatchElement.setGeometry(subMeshStaticBatch); staBatchElement.material = staLastElement.material; var staRootOwner = subMeshStaticBatch.batchOwner; var staBatchTransform = staRootOwner ? staRootOwner._transform : null; staBatchElement.setTransform(staBatchTransform); staBatchElement.render = this.render; staBatchElement.renderSubShader = staLastElement.renderSubShader; var staBatchList = staBatchElement.staticBatchElementList; staBatchList.length = 0; staBatchList.add(staLastElement); staBatchList.add(this); elements[queueElements.length - 1] = staBatchElement; } queue.lastTransparentBatched = true; } } else { queueElements.add(this); queue.lastTransparentBatched = false; } } else if (this.renderSubShader._owner._enableInstancing && Laya.LayaGL.layaGPUInstance.supportInstance() && this.render.lightmapIndex < 0) { var subMesh = this._geometry; var insManager = ILaya3D.MeshRenderDynamicBatchManager.instance; var insLastElement = queue.lastTransparentRenderElement; if (insLastElement) { var insLastRender = insLastElement.render; if (insLastElement._geometry._getType() !== this._geometry._getType() || insLastElement._geometry !== subMesh || insLastElement.material !== this.material || insLastRender.receiveShadow !== this.render.receiveShadow) { queueElements.add(this); queue.lastTransparentBatched = false; } else { if (queue.lastTransparentBatched) { var instanceBatchElementList = elements[queueElements.length - 1].instanceBatchElementList; if (instanceBatchElementList.length === SubMeshInstanceBatch.instance.maxInstanceCount) { queueElements.add(this); queue.lastTransparentBatched = false; } else { instanceBatchElementList.add(this); queue.lastTransparentBatched = true; } } else { var insBatchElement = insManager._getBatchRenderElementFromPool(); insBatchElement.renderType = RenderElement.RENDERTYPE_INSTANCEBATCH; insBatchElement.setGeometry(SubMeshInstanceBatch.instance); insBatchElement.material = insLastElement.material; insBatchElement.setTransform(null); insBatchElement.render = this.render; insBatchElement.instanceSubMesh = subMesh; insBatchElement.renderSubShader = insLastElement.renderSubShader; var insBatchList = insBatchElement.instanceBatchElementList; insBatchList.length = 0; insBatchList.add(insLastElement); insBatchList.add(this); elements[queueElements.length - 1] = insBatchElement; queue.lastTransparentBatched = true; } } } else { queueElements.add(this); queue.lastTransparentBatched = false; } } else if (this._dynamicVertexBatch) { var verDec = this._geometry._vertexBuffer.vertexDeclaration; var dynManager = ILaya3D.MeshRenderDynamicBatchManager.instance; var dynLastElement = queue.lastTransparentRenderElement; if (dynLastElement) { var dynLastRender = dynLastElement.render; if (!dynLastElement._dynamicVertexBatch || dynLastElement._geometry._getType() !== this._geometry._getType() || dynLastElement._geometry._vertexBuffer._vertexDeclaration !== verDec || dynLastElement.material !== this.material || dynLastRender.receiveShadow !== this.render.receiveShadow || dynLastRender.lightmapIndex !== this.render.lightmapIndex) { queueElements.add(this); queue.lastTransparentBatched = false; } else { if (queue.lastTransparentBatched) { elements[queueElements.length - 1].vertexBatchElementList.add((this)); } else { var dynBatchElement = dynManager._getBatchRenderElementFromPool(); dynBatchElement.renderType = RenderElement.RENDERTYPE_VERTEXBATCH; dynBatchElement.setGeometry(ILaya3D.SubMeshDynamicBatch.instance); dynBatchElement.material = dynLastElement.material; dynBatchElement.setTransform(null); dynBatchElement.render = this.render; dynBatchElement.vertexBatchVertexDeclaration = verDec; dynBatchElement.renderSubShader = dynLastElement.renderSubShader; var dynBatchList = dynBatchElement.vertexBatchElementList; dynBatchList.length = 0; dynBatchList.add(dynLastElement); dynBatchList.add(this); elements[queueElements.length - 1] = dynBatchElement; } queue.lastTransparentBatched = true; } } else { queueElements.add(this); queue.lastTransparentBatched = false; } } else { queueElements.add(this); } queue.lastTransparentRenderElement = this; } getInvertFront() { switch (this.renderType) { case RenderElement.RENDERTYPE_NORMAL: return this._transform._isFrontFaceInvert; case RenderElement.RENDERTYPE_STATICBATCH: case RenderElement.RENDERTYPE_VERTEXBATCH: return false; case RenderElement.RENDERTYPE_INSTANCEBATCH: return this.instanceBatchElementList.elements[0]._transform._isFrontFaceInvert; default: throw "SubMeshRenderElement: unknown renderType"; } } destroy() { super.destroy(); this._dynamicWorldPositions = null; this._dynamicWorldNormals = null; this.staticBatch = null; this.staticBatchElementList = null; this.vertexBatchElementList = null; this.vertexBatchVertexDeclaration = null; } } class StaticBatchManager { constructor() { this._initBatchSprites = []; this._staticBatches = {}; this._batchRenderElementPoolIndex = 0; this._batchRenderElementPool = []; } static _addToStaticBatchQueue(sprite3D, renderableSprite3D) { if (sprite3D instanceof RenderableSprite3D) renderableSprite3D.push(sprite3D); for (var i = 0, n = sprite3D.numChildren; i < n; i++) StaticBatchManager._addToStaticBatchQueue(sprite3D._children[i], renderableSprite3D); } static _registerManager(manager) { StaticBatchManager._managers.push(manager); } static combine(staticBatchRoot, renderableSprite3Ds = null) { if (!renderableSprite3Ds) { renderableSprite3Ds = []; if (staticBatchRoot) StaticBatchManager._addToStaticBatchQueue(staticBatchRoot, renderableSprite3Ds); } var batchSpritesCount = renderableSprite3Ds.length; if (batchSpritesCount > 0) { for (var i = 0; i < batchSpritesCount; i++) { var sprite = renderableSprite3Ds[i]; if (!sprite.destroyed) { if (sprite._render._isPartOfStaticBatch) console.warn("StaticBatchManager: Sprite " + sprite.name + " has a part of Static Batch,it will be ignore."); else sprite._addToInitStaticBatchManager(); } } for (var k = 0, m = StaticBatchManager._managers.length; k < m; k++) { var manager = StaticBatchManager._managers[k]; manager._initStaticBatchs(staticBatchRoot); } } } _partition(items, left, right) { var pivot = items[Math.floor((right + left) / 2)]; while (left <= right) { while (this._compare(items[left], pivot) < 0) left++; while (this._compare(items[right], pivot) > 0) right--; if (left < right) { var temp = items[left]; items[left] = items[right]; items[right] = temp; left++; right--; } else if (left === right) { left++; break; } } return left; } _quickSort(items, left, right) { if (items.length > 1) { var index = this._partition(items, left, right); var leftIndex = index - 1; if (left < leftIndex) this._quickSort(items, left, leftIndex); if (index < right) this._quickSort(items, index, right); } } _compare(left, right) { throw "StaticBatch:must override this function."; } _initStaticBatchs(rootSprite) { throw "StaticBatch:must override this function."; } _getBatchRenderElementFromPool() { throw "StaticBatch:must override this function."; } _addBatchSprite(renderableSprite3D) { this._initBatchSprites.push(renderableSprite3D); } _clear() { this._batchRenderElementPoolIndex = 0; } _garbageCollection() { throw "StaticBatchManager: must override it."; } dispose() { this._staticBatches = null; } } StaticBatchManager._managers = []; class SubMeshStaticBatch extends GeometryElement { constructor(batchOwner, vertexDeclaration) { super(); this._bufferState = new BufferState(); this._batchID = SubMeshStaticBatch._batchIDCounter++; this._batchElements = []; this._currentBatchVertexCount = 0; this._currentBatchIndexCount = 0; this._vertexDeclaration = vertexDeclaration; this.batchOwner = batchOwner; } _getStaticBatchBakedVertexs(batchVertices, batchOffset, batchOwnerTransform, transform, render, mesh) { var vertexBuffer = mesh._vertexBuffer; var vertexDeclaration = vertexBuffer.vertexDeclaration; var positionOffset = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_POSITION0)._offset / 4; var normalElement = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_NORMAL0); var normalOffset = normalElement ? normalElement._offset / 4 : -1; var colorElement = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_COLOR0); var colorOffset = colorElement ? colorElement._offset / 4 : -1; var uv0Element = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_TEXTURECOORDINATE0); var uv0Offset = uv0Element ? uv0Element._offset / 4 : -1; var uv1Element = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_TEXTURECOORDINATE1); var uv1Offset = uv1Element ? uv1Element._offset / 4 : -1; var tangentElement = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_TANGENT0); var sTangentOffset = tangentElement ? tangentElement._offset / 4 : -1; var bakeVertexFloatCount = 18; var oriVertexFloatCount = vertexDeclaration.vertexStride / 4; var oriVertexes = vertexBuffer.getFloat32Data(); var worldMat; if (batchOwnerTransform) { var rootMat = batchOwnerTransform.worldMatrix; rootMat.invert(SubMeshStaticBatch._tempMatrix4x40); worldMat = SubMeshStaticBatch._tempMatrix4x41; Matrix4x4.multiply(SubMeshStaticBatch._tempMatrix4x40, transform.worldMatrix, worldMat); } else { worldMat = transform.worldMatrix; } var normalMat = SubMeshStaticBatch._tempMatrix4x42; worldMat.invert(normalMat); normalMat.transpose(); var rotation = SubMeshStaticBatch._tempQuaternion0; worldMat.decomposeTransRotScale(SubMeshStaticBatch._tempVector30, rotation, SubMeshStaticBatch._tempVector31); var lightmapScaleOffset = render.lightmapScaleOffset; var vertexCount = mesh.vertexCount; for (var i = 0; i < vertexCount; i++) { var oriOffset = i * oriVertexFloatCount; var bakeOffset = (i + batchOffset) * bakeVertexFloatCount; Utils3D.transformVector3ArrayToVector3ArrayCoordinate(oriVertexes, oriOffset + positionOffset, worldMat, batchVertices, bakeOffset + 0); if (normalOffset !== -1) Utils3D.transformVector3ArrayToVector3ArrayNormal(oriVertexes, oriOffset + normalOffset, normalMat, batchVertices, bakeOffset + 3); var j, m; var bakOff = bakeOffset + 6; if (colorOffset !== -1) { var oriOff = oriOffset + colorOffset; for (j = 0, m = 4; j < m; j++) batchVertices[bakOff + j] = oriVertexes[oriOff + j]; } else { for (j = 0, m = 4; j < m; j++) batchVertices[bakOff + j] = 1.0; } if (uv0Offset !== -1) { var absUv0Offset = oriOffset + uv0Offset; batchVertices[bakeOffset + 10] = oriVertexes[absUv0Offset]; batchVertices[bakeOffset + 11] = oriVertexes[absUv0Offset + 1]; } if (lightmapScaleOffset) { if (uv1Offset !== -1) Utils3D.transformLightingMapTexcoordArray(oriVertexes, oriOffset + uv1Offset, lightmapScaleOffset, batchVertices, bakeOffset + 12); else Utils3D.transformLightingMapTexcoordArray(oriVertexes, oriOffset + uv0Offset, lightmapScaleOffset, batchVertices, bakeOffset + 12); } if (sTangentOffset !== -1) { var absSTanegntOffset = oriOffset + sTangentOffset; batchVertices[bakeOffset + 14] = oriVertexes[absSTanegntOffset]; batchVertices[bakeOffset + 15] = oriVertexes[absSTanegntOffset + 1]; batchVertices[bakeOffset + 16] = oriVertexes[absSTanegntOffset + 2]; batchVertices[bakeOffset + 17] = oriVertexes[absSTanegntOffset + 3]; } } return vertexCount; } addTest(sprite) { var vertexCount; var subMeshVertexCount = sprite.meshFilter.sharedMesh.vertexCount; vertexCount = this._currentBatchVertexCount + subMeshVertexCount; if (vertexCount > SubMeshStaticBatch.maxBatchVertexCount) return false; return true; } add(sprite) { var mesh = sprite.meshFilter.sharedMesh; var subMeshVertexCount = mesh.vertexCount; this._batchElements.push(sprite); var render = sprite._render; render._isPartOfStaticBatch = true; render._staticBatch = this; var renderElements = render._renderElements; for (var i = 0, n = renderElements.length; i < n; i++) renderElements[i].staticBatch = this; this._currentBatchIndexCount += mesh._indexBuffer.indexCount; this._currentBatchVertexCount += subMeshVertexCount; } remove(sprite) { var mesh = sprite.meshFilter.sharedMesh; var index = this._batchElements.indexOf(sprite); if (index !== -1) { this._batchElements.splice(index, 1); var renderElements = sprite._render._renderElements; for (var i = 0, n = renderElements.length; i < n; i++) renderElements[i].staticBatch = null; this._currentBatchIndexCount = this._currentBatchIndexCount - mesh._indexBuffer.indexCount; this._currentBatchVertexCount = this._currentBatchVertexCount - mesh.vertexCount; sprite._render._isPartOfStaticBatch = false; } } finishInit() { if (this._vertexBuffer) { this._vertexBuffer.destroy(); this._indexBuffer.destroy(); Laya.Resource._addGPUMemory(-(this._vertexBuffer._byteLength + this._indexBuffer._byteLength)); } var gl = Laya.LayaGL.instance; var batchVertexCount = 0; var batchIndexCount = 0; var rootOwner = this.batchOwner; var floatStride = this._vertexDeclaration.vertexStride / 4; var vertexDatas = new Float32Array(floatStride * this._currentBatchVertexCount); var indexDatas = new Uint16Array(this._currentBatchIndexCount); this._vertexBuffer = new VertexBuffer3D(this._vertexDeclaration.vertexStride * this._currentBatchVertexCount, gl.STATIC_DRAW); this._vertexBuffer.vertexDeclaration = this._vertexDeclaration; this._indexBuffer = new IndexBuffer3D(exports.IndexFormat.UInt16, this._currentBatchIndexCount, gl.STATIC_DRAW); for (var i = 0, n = this._batchElements.length; i < n; i++) { var sprite = this._batchElements[i]; var mesh = sprite.meshFilter.sharedMesh; var meshVerCount = this._getStaticBatchBakedVertexs(vertexDatas, batchVertexCount, rootOwner ? rootOwner._transform : null, sprite._transform, sprite._render, mesh); var indices = mesh._indexBuffer.getData(); var indexOffset = batchVertexCount; var indexEnd = batchIndexCount + indices.length; var elements = sprite._render._renderElements; for (var j = 0, m = mesh.subMeshCount; j < m; j++) { var subMesh = mesh._subMeshes[j]; var start = batchIndexCount + subMesh._indexStart; var element = elements[j]; element.staticBatchIndexStart = start; element.staticBatchIndexEnd = start + subMesh._indexCount; } indexDatas.set(indices, batchIndexCount); var k; var isInvert = rootOwner ? (sprite._transform._isFrontFaceInvert !== rootOwner.transform._isFrontFaceInvert) : sprite._transform._isFrontFaceInvert; if (isInvert) { for (k = batchIndexCount; k < indexEnd; k += 3) { indexDatas[k] = indexOffset + indexDatas[k]; var index1 = indexDatas[k + 1]; var index2 = indexDatas[k + 2]; indexDatas[k + 1] = indexOffset + index2; indexDatas[k + 2] = indexOffset + index1; } } else { for (k = batchIndexCount; k < indexEnd; k += 3) { indexDatas[k] = indexOffset + indexDatas[k]; indexDatas[k + 1] = indexOffset + indexDatas[k + 1]; indexDatas[k + 2] = indexOffset + indexDatas[k + 2]; } } batchIndexCount += indices.length; batchVertexCount += meshVerCount; } this._vertexBuffer.setData(vertexDatas.buffer); this._indexBuffer.setData(indexDatas); var memorySize = this._vertexBuffer._byteLength + this._indexBuffer._byteLength; Laya.Resource._addGPUMemory(memorySize); this._bufferState.bind(); this._bufferState.applyVertexBuffer(this._vertexBuffer); this._bufferState.applyIndexBuffer(this._indexBuffer); this._bufferState.unBind(); } _render(state) { this._bufferState.bind(); var gl = Laya.LayaGL.instance; var element = state.renderElement; var staticBatchElementList = element.staticBatchElementList; var batchElementList = staticBatchElementList.elements; var from = 0; var end = 0; var count = staticBatchElementList.length; for (var i = 1; i < count; i++) { var lastElement = batchElementList[i - 1]; if (lastElement.staticBatchIndexEnd === batchElementList[i].staticBatchIndexStart) { end++; continue; } else { var start = batchElementList[from].staticBatchIndexStart; var indexCount = batchElementList[end].staticBatchIndexEnd - start; gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, start * 2); from = ++end; Laya.Stat.trianglesFaces += indexCount / 3; } } start = batchElementList[from].staticBatchIndexStart; indexCount = batchElementList[end].staticBatchIndexEnd - start; gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, start * 2); Laya.Stat.renderBatches++; Laya.Stat.savedRenderBatches += count - 1; Laya.Stat.trianglesFaces += indexCount / 3; } dispose() { var memorySize = this._vertexBuffer._byteLength + this._indexBuffer._byteLength; Laya.Resource._addGPUMemory(-memorySize); this._batchElements = null; this.batchOwner = null; this._vertexDeclaration = null; this._bufferState.destroy(); this._vertexBuffer.destroy(); this._indexBuffer.destroy(); this._vertexBuffer = null; this._indexBuffer = null; this._bufferState = null; } } SubMeshStaticBatch._tempVector30 = new Vector3(); SubMeshStaticBatch._tempVector31 = new Vector3(); SubMeshStaticBatch._tempQuaternion0 = new Quaternion(); SubMeshStaticBatch._tempMatrix4x40 = new Matrix4x4(); SubMeshStaticBatch._tempMatrix4x41 = new Matrix4x4(); SubMeshStaticBatch._tempMatrix4x42 = new Matrix4x4(); SubMeshStaticBatch.maxBatchVertexCount = 65535; SubMeshStaticBatch._batchIDCounter = 0; class MeshRenderStaticBatchManager extends StaticBatchManager { constructor() { super(); this._opaqueBatchMarks = []; this._updateCountMark = 0; } static __init__() { MeshRenderStaticBatchManager._verDec = VertexMesh.getVertexDeclaration("POSITION,NORMAL,COLOR,UV,UV1,TANGENT"); } _compare(left, right) { var lRender = left._render, rRender = right._render; var leftGeo = left.meshFilter.sharedMesh, rightGeo = right.meshFilter.sharedMesh; var lightOffset = lRender.lightmapIndex - rRender.lightmapIndex; if (lightOffset === 0) { var receiveShadowOffset = (lRender.receiveShadow ? 1 : 0) - (rRender.receiveShadow ? 1 : 0); if (receiveShadowOffset === 0) { var materialOffset = (lRender.sharedMaterial && rRender.sharedMaterial) ? lRender.sharedMaterial.id - rRender.sharedMaterial.id : 0; if (materialOffset === 0) { var verDec = leftGeo._vertexBuffer.vertexDeclaration.id - rightGeo._vertexBuffer.vertexDeclaration.id; if (verDec === 0) { return rightGeo._indexBuffer.indexCount - leftGeo._indexBuffer.indexCount; } else { return verDec; } } else { return materialOffset; } } else { return receiveShadowOffset; } } else { return lightOffset; } } _getBatchRenderElementFromPool() { var renderElement = this._batchRenderElementPool[this._batchRenderElementPoolIndex++]; if (!renderElement) { renderElement = new SubMeshRenderElement(); this._batchRenderElementPool[this._batchRenderElementPoolIndex - 1] = renderElement; renderElement.staticBatchElementList = new SingletonList(); } return renderElement; } _getStaticBatch(staticBatches, rootOwner, number) { var subMeshStaticBatch = staticBatches[number]; if (!subMeshStaticBatch) { subMeshStaticBatch = staticBatches[number] = new SubMeshStaticBatch(rootOwner, MeshRenderStaticBatchManager._verDec); this._staticBatches[subMeshStaticBatch._batchID] = subMeshStaticBatch; } return subMeshStaticBatch; } _initStaticBatchs(rootOwner) { var initBatchSprites = this._initBatchSprites; this._quickSort(initBatchSprites, 0, initBatchSprites.length - 1); var staticBatches = []; var lastCanMerage = false; var curStaticBatch; var batchNumber = 0; for (var i = 0, n = initBatchSprites.length; i < n; i++) { var sprite = initBatchSprites[i]; if (lastCanMerage) { if (curStaticBatch.addTest(sprite)) { curStaticBatch.add(sprite); } else { lastCanMerage = false; batchNumber++; } } else { var lastIndex = n - 1; if (i !== lastIndex) { curStaticBatch = this._getStaticBatch(staticBatches, rootOwner, batchNumber); curStaticBatch.add(sprite); lastCanMerage = true; } } } for (i = 0, n = staticBatches.length; i < n; i++) { var staticBatch = staticBatches[i]; staticBatch && staticBatch.finishInit(); } this._initBatchSprites.length = 0; } _removeRenderSprite(sprite) { var render = sprite._render; var staticBatch = render._staticBatch; var batchElements = staticBatch._batchElements; var index = batchElements.indexOf(sprite); if (index !== -1) { batchElements.splice(index, 1); render._staticBatch = null; var renderElements = render._renderElements; for (var i = 0, n = renderElements.length; i < n; i++) renderElements[i].staticBatch = null; } if (batchElements.length === 0) { delete this._staticBatches[staticBatch._batchID]; staticBatch.dispose(); } } _clear() { super._clear(); this._updateCountMark++; } _garbageCollection() { for (var key in this._staticBatches) { var staticBatch = this._staticBatches[key]; if (staticBatch._batchElements.length === 0) { staticBatch.dispose(); delete this._staticBatches[key]; } } } getBatchOpaquaMark(lightMapIndex, receiveShadow, materialID, staticBatchID) { var receiveShadowIndex = receiveShadow ? 1 : 0; var staLightMapMarks = (this._opaqueBatchMarks[lightMapIndex]) || (this._opaqueBatchMarks[lightMapIndex] = []); var staReceiveShadowMarks = (staLightMapMarks[receiveShadowIndex]) || (staLightMapMarks[receiveShadowIndex] = []); var staMaterialMarks = (staReceiveShadowMarks[materialID]) || (staReceiveShadowMarks[materialID] = []); return (staMaterialMarks[staticBatchID]) || (staMaterialMarks[staticBatchID] = new BatchMark); } } MeshRenderStaticBatchManager.instance = new MeshRenderStaticBatchManager(); class BaseRender extends Laya.EventDispatcher { constructor(owner) { super(); this._lightmapScaleOffset = new Vector4(1, 1, 0, 0); this._indexInList = -1; this._indexInCastShadowList = -1; this._boundsChange = true; this._castShadow = false; this._supportOctree = true; this._sharedMaterials = []; this._renderMark = -1; this._indexInOctreeMotionList = -1; this._updateMark = -1; this._updateRenderType = -1; this._isPartOfStaticBatch = false; this._staticBatch = null; this._id = ++BaseRender._uniqueIDCounter; this._indexInCastShadowList = -1; this._bounds = new Bounds(Vector3._ZERO, Vector3._ZERO); if (Laya.Render.supportWebGLPlusCulling) { var length = FrustumCulling._cullingBufferLength; this._cullingBufferIndex = length; var cullingBuffer = FrustumCulling._cullingBuffer; var resizeLength = length + 7; if (resizeLength >= cullingBuffer.length) { var temp = cullingBuffer; cullingBuffer = FrustumCulling._cullingBuffer = new Float32Array(cullingBuffer.length + 4096); cullingBuffer.set(temp, 0); } cullingBuffer[length] = 2; FrustumCulling._cullingBufferLength = resizeLength; } this._renderElements = []; this._owner = owner; this._enable = true; this._materialsInstance = []; this._shaderValues = new ShaderData(null); this.lightmapIndex = -1; this.receiveShadow = false; this.sortingFudge = 0.0; (owner) && (this._owner.transform.on(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange)); } get id() { return this._id; } get lightmapIndex() { return this._lightmapIndex; } set lightmapIndex(value) { this._lightmapIndex = value; } get lightmapScaleOffset() { return this._lightmapScaleOffset; } set lightmapScaleOffset(value) { if (!value) throw "BaseRender: lightmapScaleOffset can't be null."; this._lightmapScaleOffset = value; this._shaderValues.setVector(RenderableSprite3D.LIGHTMAPSCALEOFFSET, value); } get enable() { return this._enable; } set enable(value) { this._enable = !!value; } get material() { var material = this._sharedMaterials[0]; if (material && !this._materialsInstance[0]) { var insMat = this._getInstanceMaterial(material, 0); var renderElement = this._renderElements[0]; (renderElement) && (renderElement.material = insMat); } return this._sharedMaterials[0]; } set material(value) { this.sharedMaterial = value; } get materials() { for (var i = 0, n = this._sharedMaterials.length; i < n; i++) { if (!this._materialsInstance[i]) { var insMat = this._getInstanceMaterial(this._sharedMaterials[i], i); var renderElement = this._renderElements[i]; (renderElement) && (renderElement.material = insMat); } } return this._sharedMaterials.slice(); } set materials(value) { this.sharedMaterials = value; } get sharedMaterial() { return this._sharedMaterials[0]; } set sharedMaterial(value) { var lastValue = this._sharedMaterials[0]; if (lastValue !== value) { this._sharedMaterials[0] = value; this._materialsInstance[0] = false; this._changeMaterialReference(lastValue, value); var renderElement = this._renderElements[0]; (renderElement) && (renderElement.material = value); } } get sharedMaterials() { return this._sharedMaterials.slice(); } set sharedMaterials(value) { var materialsInstance = this._materialsInstance; var sharedMats = this._sharedMaterials; for (var i = 0, n = sharedMats.length; i < n; i++) { var lastMat = sharedMats[i]; (lastMat) && (lastMat._removeReference()); } if (value) { var count = value.length; materialsInstance.length = count; sharedMats.length = count; for (i = 0; i < count; i++) { lastMat = sharedMats[i]; var mat = value[i]; if (lastMat !== mat) { materialsInstance[i] = false; var renderElement = this._renderElements[i]; (renderElement) && (renderElement.material = mat); } if (mat) { mat._addReference(); } sharedMats[i] = mat; } } else { throw new Error("BaseRender: shadredMaterials value can't be null."); } } get bounds() { if (this._boundsChange) { this._calculateBoundingBox(); this._boundsChange = false; } return this._bounds; } set receiveShadow(value) { if (this._receiveShadow !== value) { this._receiveShadow = value; if (value) this._shaderValues.addDefine(RenderableSprite3D.SHADERDEFINE_RECEIVE_SHADOW); else this._shaderValues.removeDefine(RenderableSprite3D.SHADERDEFINE_RECEIVE_SHADOW); } } get receiveShadow() { return this._receiveShadow; } get castShadow() { return this._castShadow; } set castShadow(value) { this._castShadow = value; } get isPartOfStaticBatch() { return this._isPartOfStaticBatch; } get isRender() { return this._renderMark == -1 || this._renderMark == (Laya.Stat.loopCount - 1); } _getOctreeNode() { return this._octreeNode; } _setOctreeNode(value) { this._octreeNode = value; } _getIndexInMotionList() { return this._indexInOctreeMotionList; } _setIndexInMotionList(value) { this._indexInOctreeMotionList = value; } _changeMaterialReference(lastValue, value) { (lastValue) && (lastValue._removeReference()); value._addReference(); } _getInstanceMaterial(material, index) { var insMat = material.clone(); insMat.name = insMat.name + "(Instance)"; this._materialsInstance[index] = true; this._changeMaterialReference(this._sharedMaterials[index], insMat); this._sharedMaterials[index] = insMat; return insMat; } _applyLightMapParams() { var lightMaps = this._scene.lightmaps; var shaderValues = this._shaderValues; var lightmapIndex = this._lightmapIndex; if (lightmapIndex >= 0 && lightmapIndex < lightMaps.length) { var lightMap = lightMaps[lightmapIndex]; shaderValues.setTexture(RenderableSprite3D.LIGHTMAP, lightMap.lightmapColor); shaderValues.addDefine(RenderableSprite3D.SAHDERDEFINE_LIGHTMAP); if (lightMap.lightmapDirection) { shaderValues.setTexture(RenderableSprite3D.LIGHTMAP_DIRECTION, lightMap.lightmapDirection); shaderValues.addDefine(RenderableSprite3D.SHADERDEFINE_LIGHTMAP_DIRECTIONAL); } else { shaderValues.removeDefine(RenderableSprite3D.SHADERDEFINE_LIGHTMAP_DIRECTIONAL); } } else { shaderValues.removeDefine(RenderableSprite3D.SAHDERDEFINE_LIGHTMAP); shaderValues.removeDefine(RenderableSprite3D.SHADERDEFINE_LIGHTMAP_DIRECTIONAL); } } _onWorldMatNeedChange(flag) { this._boundsChange = true; if (this._octreeNode) { flag &= Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDSCALE; if (flag) { if (this._indexInOctreeMotionList === -1) this._octreeNode._octree.addMotionObject(this); } } } _calculateBoundingBox() { throw ("BaseRender: must override it."); } _getIndexInList() { return this._indexInList; } _setIndexInList(index) { this._indexInList = index; } _setBelongScene(scene) { this._scene = scene; } _needRender(boundFrustum, context) { return true; } _renderUpdate(context, transform) { } _renderUpdateWithCamera(context, transform) { } _revertBatchRenderUpdate(context) { } _destroy() { (this._indexInOctreeMotionList !== -1) && (this._octreeNode._octree.removeMotionObject(this)); this.offAll(); var i = 0, n = 0; for (i = 0, n = this._renderElements.length; i < n; i++) this._renderElements[i].destroy(); for (i = 0, n = this._sharedMaterials.length; i < n; i++) (this._sharedMaterials[i].destroyed) || (this._sharedMaterials[i]._removeReference()); this._renderElements = null; this._owner = null; this._sharedMaterials = null; this._bounds = null; this._lightmapScaleOffset = null; } markAsUnStatic() { if (this._isPartOfStaticBatch) { MeshRenderStaticBatchManager.instance._removeRenderSprite(this._owner); this._isPartOfStaticBatch = false; } } } BaseRender._tempBoundBoxCorners = [new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3()]; BaseRender._uniqueIDCounter = 0; BaseRender._defaultLightmapScaleOffset = new Vector4(1.0, 1.0, 0.0, 0.0); class PixelLineRenderer extends BaseRender { constructor(owner) { super(owner); this._projectionViewWorldMatrix = new Matrix4x4(); } _calculateBoundingBox() { var worldMat = this._owner.transform.worldMatrix; var lineFilter = this._owner._geometryFilter; lineFilter._reCalculateBound(); lineFilter._bounds._tranform(worldMat, this._bounds); if (Laya.Render.supportWebGLPlusCulling) { var min = this._bounds.getMin(); var max = this._bounds.getMax(); var buffer = FrustumCulling._cullingBuffer; buffer[this._cullingBufferIndex + 1] = min.x; buffer[this._cullingBufferIndex + 2] = min.y; buffer[this._cullingBufferIndex + 3] = min.z; buffer[this._cullingBufferIndex + 4] = max.x; buffer[this._cullingBufferIndex + 5] = max.y; buffer[this._cullingBufferIndex + 6] = max.z; } } _renderUpdateWithCamera(context, transform) { var projectionView = context.projectionViewMatrix; var sv = this._shaderValues; if (transform) { var worldMat = transform.worldMatrix; sv.setMatrix4x4(Sprite3D.WORLDMATRIX, worldMat); Matrix4x4.multiply(projectionView, worldMat, this._projectionViewWorldMatrix); sv.setMatrix4x4(Sprite3D.MVPMATRIX, this._projectionViewWorldMatrix); } else { sv.setMatrix4x4(Sprite3D.WORLDMATRIX, Matrix4x4.DEFAULT); sv.setMatrix4x4(Sprite3D.MVPMATRIX, projectionView); } } } class PixelLineSprite3D extends RenderableSprite3D { constructor(maxCount = 2, name = null) { super(name); this._geometryFilter = new PixelLineFilter(this, maxCount); this._render = new PixelLineRenderer(this); this._changeRenderObjects(this._render, 0, PixelLineMaterial.defaultMaterial); } get maxLineCount() { return this._geometryFilter._maxLineCount; } set maxLineCount(value) { this._geometryFilter._resizeLineData(value); this._geometryFilter._lineCount = Math.min(this._geometryFilter._lineCount, value); } get lineCount() { return this._geometryFilter._lineCount; } set lineCount(value) { if (value > this.maxLineCount) throw "PixelLineSprite3D: lineCount can't large than maxLineCount"; else this._geometryFilter._lineCount = value; } get pixelLineRenderer() { return this._render; } _changeRenderObjects(sender, index, material) { var renderObjects = this._render._renderElements; (material) || (material = PixelLineMaterial.defaultMaterial); var renderElement = renderObjects[index]; (renderElement) || (renderElement = renderObjects[index] = new RenderElement()); renderElement.setTransform(this._transform); renderElement.setGeometry(this._geometryFilter); renderElement.render = this._render; renderElement.material = material; } addLine(startPosition, endPosition, startColor, endColor) { if (this._geometryFilter._lineCount !== this._geometryFilter._maxLineCount) this._geometryFilter._updateLineData(this._geometryFilter._lineCount++, startPosition, endPosition, startColor, endColor); else throw "PixelLineSprite3D: lineCount has equal with maxLineCount."; } addLines(lines) { var lineCount = this._geometryFilter._lineCount; var addCount = lines.length; if (lineCount + addCount > this._geometryFilter._maxLineCount) { throw "PixelLineSprite3D: lineCount plus lines count must less than maxLineCount."; } else { this._geometryFilter._updateLineDatas(lineCount, lines); this._geometryFilter._lineCount += addCount; } } removeLine(index) { if (index < this._geometryFilter._lineCount) this._geometryFilter._removeLineData(index); else throw "PixelLineSprite3D: index must less than lineCount."; } setLine(index, startPosition, endPosition, startColor, endColor) { if (index < this._geometryFilter._lineCount) this._geometryFilter._updateLineData(index, startPosition, endPosition, startColor, endColor); else throw "PixelLineSprite3D: index must less than lineCount."; } getLine(index, out) { if (index < this.lineCount) this._geometryFilter._getLineData(index, out); else throw "PixelLineSprite3D: index must less than lineCount."; } clear() { this._geometryFilter._lineCount = 0; } _create() { return new PixelLineSprite3D(); } } class RenderQueue { constructor(isTransparent = false) { this.isTransparent = false; this.elements = new SingletonList(); this.lastTransparentRenderElement = null; this.lastTransparentBatched = false; this.isTransparent = isTransparent; } _compare(left, right) { var renderQueue = left.material.renderQueue - right.material.renderQueue; if (renderQueue === 0) { var sort = this.isTransparent ? right.render._distanceForSort - left.render._distanceForSort : left.render._distanceForSort - right.render._distanceForSort; return sort + right.render.sortingFudge - left.render.sortingFudge; } else { return renderQueue; } } _partitionRenderObject(left, right) { var elements = this.elements.elements; var pivot = elements[Math.floor((right + left) / 2)]; while (left <= right) { while (this._compare(elements[left], pivot) < 0) left++; while (this._compare(elements[right], pivot) > 0) right--; if (left < right) { var temp = elements[left]; elements[left] = elements[right]; elements[right] = temp; left++; right--; } else if (left === right) { left++; break; } } return left; } _quickSort(left, right) { if (this.elements.length > 1) { var index = this._partitionRenderObject(left, right); var leftIndex = index - 1; if (left < leftIndex) this._quickSort(left, leftIndex); if (index < right) this._quickSort(index, right); } } _render(context) { var elements = this.elements.elements; for (var i = 0, n = this.elements.length; i < n; i++) elements[i]._render(context); } clear() { this.elements.length = 0; this.lastTransparentRenderElement = null; this.lastTransparentBatched = false; } } class BoundsOctreeNode { constructor(octree, parent, baseLength, center) { this._bounds = new BoundBox(new Vector3(), new Vector3()); this._objects = []; this._isContaion = false; this.center = new Vector3(); this.baseLength = 0.0; this._setValues(octree, parent, baseLength, center); } static _encapsulates(outerBound, innerBound) { return CollisionUtils.boxContainsBox(outerBound, innerBound) == ContainmentType.Contains; } _setValues(octree, parent, baseLength, center) { this._octree = octree; this._parent = parent; this.baseLength = baseLength; center.cloneTo(this.center); var min = this._bounds.min; var max = this._bounds.max; var halfSize = (octree._looseness * baseLength) / 2; min.setValue(center.x - halfSize, center.y - halfSize, center.z - halfSize); max.setValue(center.x + halfSize, center.y + halfSize, center.z + halfSize); } _getChildBound(index) { if (this._children != null && this._children[index]) { return this._children[index]._bounds; } else { var quarter = this.baseLength / 4; var halfChildSize = ((this.baseLength / 2) * this._octree._looseness) / 2; var bounds = BoundsOctreeNode._tempBoundBox; var min = bounds.min; var max = bounds.max; switch (index) { case 0: min.x = this.center.x - quarter - halfChildSize; min.y = this.center.y + quarter - halfChildSize; min.z = this.center.z - quarter - halfChildSize; max.x = this.center.x - quarter + halfChildSize; max.y = this.center.y + quarter + halfChildSize; max.z = this.center.z - quarter + halfChildSize; break; case 1: min.x = this.center.x + quarter - halfChildSize; min.y = this.center.y + quarter - halfChildSize; min.z = this.center.z - quarter - halfChildSize; max.x = this.center.x + quarter + halfChildSize; max.y = this.center.y + quarter + halfChildSize; max.z = this.center.z - quarter + halfChildSize; break; case 2: min.x = this.center.x - quarter - halfChildSize; min.y = this.center.y + quarter - halfChildSize; min.z = this.center.z + quarter - halfChildSize; max.x = this.center.x - quarter + halfChildSize; max.y = this.center.y + quarter + halfChildSize; max.z = this.center.z + quarter + halfChildSize; break; case 3: min.x = this.center.x + quarter - halfChildSize; min.y = this.center.y + quarter - halfChildSize; min.z = this.center.z + quarter - halfChildSize; max.x = this.center.x + quarter + halfChildSize; max.y = this.center.y + quarter + halfChildSize; max.z = this.center.z + quarter + halfChildSize; break; case 4: min.x = this.center.x - quarter - halfChildSize; min.y = this.center.y - quarter - halfChildSize; min.z = this.center.z - quarter - halfChildSize; max.x = this.center.x - quarter + halfChildSize; max.y = this.center.y - quarter + halfChildSize; max.z = this.center.z - quarter + halfChildSize; break; case 5: min.x = this.center.x + quarter - halfChildSize; min.y = this.center.y - quarter - halfChildSize; min.z = this.center.z - quarter - halfChildSize; max.x = this.center.x + quarter + halfChildSize; max.y = this.center.y - quarter + halfChildSize; max.z = this.center.z - quarter + halfChildSize; break; case 6: min.x = this.center.x - quarter - halfChildSize; min.y = this.center.y - quarter - halfChildSize; min.z = this.center.z + quarter - halfChildSize; max.x = this.center.x - quarter + halfChildSize; max.y = this.center.y - quarter + halfChildSize; max.z = this.center.z + quarter + halfChildSize; break; case 7: min.x = this.center.x + quarter - halfChildSize; min.y = this.center.y - quarter - halfChildSize; min.z = this.center.z + quarter - halfChildSize; max.x = this.center.x + quarter + halfChildSize; max.y = this.center.y - quarter + halfChildSize; max.z = this.center.z + quarter + halfChildSize; break; default: } return bounds; } } _getChildCenter(index) { if (this._children != null) { return this._children[index].center; } else { var quarter = this.baseLength / 4; var childCenter = BoundsOctreeNode._tempVector30; switch (index) { case 0: childCenter.x = this.center.x - quarter; childCenter.y = this.center.y + quarter; childCenter.z = this.center.z - quarter; break; case 1: childCenter.x = this.center.x + quarter; childCenter.y = this.center.y + quarter; childCenter.z = this.center.z - quarter; break; case 2: childCenter.x = this.center.x - quarter; childCenter.y = this.center.y + quarter; childCenter.z = this.center.z + quarter; break; case 3: childCenter.x = this.center.x + quarter; childCenter.y = this.center.y + quarter; childCenter.z = this.center.z + quarter; break; case 4: childCenter.x = this.center.x - quarter; childCenter.y = this.center.y - quarter; childCenter.z = this.center.z - quarter; break; case 5: childCenter.x = this.center.x + quarter; childCenter.y = this.center.y - quarter; childCenter.z = this.center.z - quarter; break; case 6: childCenter.x = this.center.x - quarter; childCenter.y = this.center.y - quarter; childCenter.z = this.center.z + quarter; break; case 7: childCenter.x = this.center.x + quarter; childCenter.y = this.center.y - quarter; childCenter.z = this.center.z + quarter; break; default: } return childCenter; } } _getChild(index) { var quarter = this.baseLength / 4; this._children || (this._children = []); switch (index) { case 0: return this._children[0] || (this._children[0] = new BoundsOctreeNode(this._octree, this, this.baseLength / 2, new Vector3(this.center.x + -quarter, this.center.y + quarter, this.center.z - quarter))); case 1: return this._children[1] || (this._children[1] = new BoundsOctreeNode(this._octree, this, this.baseLength / 2, new Vector3(this.center.x + quarter, this.center.y + quarter, this.center.z - quarter))); case 2: return this._children[2] || (this._children[2] = new BoundsOctreeNode(this._octree, this, this.baseLength / 2, new Vector3(this.center.x - quarter, this.center.y + quarter, this.center.z + quarter))); case 3: return this._children[3] || (this._children[3] = new BoundsOctreeNode(this._octree, this, this.baseLength / 2, new Vector3(this.center.x + quarter, this.center.y + quarter, this.center.z + quarter))); case 4: return this._children[4] || (this._children[4] = new BoundsOctreeNode(this._octree, this, this.baseLength / 2, new Vector3(this.center.x - quarter, this.center.y - quarter, this.center.z - quarter))); case 5: return this._children[5] || (this._children[5] = new BoundsOctreeNode(this._octree, this, this.baseLength / 2, new Vector3(this.center.x + quarter, this.center.y - quarter, this.center.z - quarter))); case 6: return this._children[6] || (this._children[6] = new BoundsOctreeNode(this._octree, this, this.baseLength / 2, new Vector3(this.center.x - quarter, this.center.y - quarter, this.center.z + quarter))); case 7: return this._children[7] || (this._children[7] = new BoundsOctreeNode(this._octree, this, this.baseLength / 2, new Vector3(this.center.x + quarter, this.center.y - quarter, this.center.z + quarter))); default: throw "BoundsOctreeNode: unknown index."; } } _shouldMerge() { var objectCount = this._objects.length; for (var i = 0; i < 8; i++) { var child = this._children[i]; if (child) { if (child._children != null) return false; objectCount += child._objects.length; } } return objectCount <= BoundsOctreeNode._NUM_OBJECTS_ALLOWED; } _mergeChildren() { for (var i = 0; i < 8; i++) { var child = this._children[i]; if (child) { child._parent = null; var childObjects = child._objects; for (var j = childObjects.length - 1; j >= 0; j--) { var childObject = childObjects[j]; this._objects.push(childObject); childObject._setOctreeNode(this); } } } this._children = null; } _merge() { if (this._children === null) { var parent = this._parent; if (parent && parent._shouldMerge()) { parent._mergeChildren(); parent._merge(); } } } _checkAddNode(object) { if (this._children == null) { if (this._objects.length < BoundsOctreeNode._NUM_OBJECTS_ALLOWED || (this.baseLength / 2) < this._octree._minSize) { return this; } for (var i = this._objects.length - 1; i >= 0; i--) { var existObject = this._objects[i]; var fitChildIndex = this._bestFitChild(existObject.bounds.getCenter()); if (BoundsOctreeNode._encapsulates(this._getChildBound(fitChildIndex), existObject.bounds._getBoundBox())) { this._objects.splice(this._objects.indexOf(existObject), 1); this._getChild(fitChildIndex)._add(existObject); } } } var newFitChildIndex = this._bestFitChild(object.bounds.getCenter()); if (BoundsOctreeNode._encapsulates(this._getChildBound(newFitChildIndex), object.bounds._getBoundBox())) return this._getChild(newFitChildIndex)._checkAddNode(object); else return this; } _add(object) { var addNode = this._checkAddNode(object); addNode._objects.push(object); object._setOctreeNode(addNode); } _remove(object) { var index = this._objects.indexOf(object); this._objects.splice(index, 1); object._setOctreeNode(null); this._merge(); } _addUp(object) { if ((CollisionUtils.boxContainsBox(this._bounds, object.bounds._getBoundBox()) === ContainmentType.Contains)) { this._add(object); return true; } else { if (this._parent) return this._parent._addUp(object); else return false; } } _getCollidingWithFrustum(cameraCullInfo, context, testVisible, customShader, replacementTag, isShadowCasterCull) { var frustum = cameraCullInfo.boundFrustum; var camPos = cameraCullInfo.position; var cullMask = cameraCullInfo.cullingMask; if (testVisible) { var type = frustum.containsBoundBox(this._bounds); Laya.Stat.octreeNodeCulling++; if (type === ContainmentType.Disjoint) return; testVisible = (type === ContainmentType.Intersects); } this._isContaion = !testVisible; var scene = context.scene; var loopCount = Laya.Stat.loopCount; for (var i = 0, n = this._objects.length; i < n; i++) { var render = this._objects[i]; var canPass; if (isShadowCasterCull) canPass = render._castShadow && render._enable; else canPass = (((Math.pow(2, render._owner._layer) & cullMask) != 0)) && render._enable; if (canPass) { if (testVisible) { Laya.Stat.frustumCulling++; if (!render._needRender(frustum, context)) continue; } render._renderMark = loopCount; render._distanceForSort = Vector3.distance(render.bounds.getCenter(), camPos); var elements = render._renderElements; for (var j = 0, m = elements.length; j < m; j++) { var element = elements[j]; element._update(scene, context, customShader, replacementTag); } } } if (this._children != null) { for (i = 0; i < 8; i++) { var child = this._children[i]; child && child._getCollidingWithFrustum(cameraCullInfo, context, testVisible, customShader, replacementTag, isShadowCasterCull); } } } _getCollidingWithBoundBox(checkBound, testVisible, result) { if (testVisible) { var type = CollisionUtils.boxContainsBox(this._bounds, checkBound); if (type === ContainmentType.Disjoint) return; testVisible = (type === ContainmentType.Intersects); } if (testVisible) { for (var i = 0, n = this._objects.length; i < n; i++) { var object = this._objects[i]; if (CollisionUtils.intersectsBoxAndBox(object.bounds._getBoundBox(), checkBound)) { result.push(object); } } } if (this._children != null) { for (i = 0; i < 8; i++) { var child = this._children[i]; child._getCollidingWithBoundBox(checkBound, testVisible, result); } } } _bestFitChild(boundCenter) { return (boundCenter.x <= this.center.x ? 0 : 1) + (boundCenter.y >= this.center.y ? 0 : 4) + (boundCenter.z <= this.center.z ? 0 : 2); } _update(object) { if (CollisionUtils.boxContainsBox(this._bounds, object.bounds._getBoundBox()) === ContainmentType.Contains) { var addNode = this._checkAddNode(object); if (addNode !== object._getOctreeNode()) { addNode._objects.push(object); object._setOctreeNode(addNode); var index = this._objects.indexOf(object); this._objects.splice(index, 1); this._merge(); } return true; } else { if (this._parent) { var sucess = this._parent._addUp(object); if (sucess) { index = this._objects.indexOf(object); this._objects.splice(index, 1); this._merge(); } return sucess; } else { return false; } } } add(object) { if (!BoundsOctreeNode._encapsulates(this._bounds, object.bounds._getBoundBox())) return false; this._add(object); return true; } remove(object) { if (object._getOctreeNode() !== this) return false; this._remove(object); return true; } update(object) { if (object._getOctreeNode() !== this) return false; return this._update(object); } shrinkIfPossible(minLength) { if (this.baseLength < minLength * 2) return this; var bestFit = -1; for (var i = 0, n = this._objects.length; i < n; i++) { var object = this._objects[i]; var newBestFit = this._bestFitChild(object.bounds.getCenter()); if (i == 0 || newBestFit == bestFit) { var childBounds = this._getChildBound(newBestFit); if (BoundsOctreeNode._encapsulates(childBounds, object.bounds._getBoundBox())) (i == 0) && (bestFit = newBestFit); else return this; } else { return this; } } if (this._children != null) { var childHadContent = false; for (i = 0, n = this._children.length; i < n; i++) { var child = this._children[i]; if (child && child.hasAnyObjects()) { if (childHadContent) return this; if (bestFit >= 0 && bestFit != i) return this; childHadContent = true; bestFit = i; } } } else { if (bestFit != -1) { var childCenter = this._getChildCenter(bestFit); this._setValues(this._octree, null, this.baseLength / 2, childCenter); } return this; } if (bestFit != -1) { var newRoot = this._children[bestFit]; newRoot._parent = null; return newRoot; } else { return this; } } hasAnyObjects() { if (this._objects.length > 0) return true; if (this._children != null) { for (var i = 0; i < 8; i++) { var child = this._children[i]; if (child && child.hasAnyObjects()) return true; } } return false; } getCollidingWithBoundBox(checkBound, result) { this._getCollidingWithBoundBox(checkBound, true, result); } getCollidingWithRay(ray, result, maxDistance = Number.MAX_VALUE) { var distance = CollisionUtils.intersectsRayAndBoxRD(ray, this._bounds); if (distance == -1 || distance > maxDistance) return; for (var i = 0, n = this._objects.length; i < n; i++) { var object = this._objects[i]; distance = CollisionUtils.intersectsRayAndBoxRD(ray, object.bounds._getBoundBox()); if (distance !== -1 && distance <= maxDistance) result.push(object); } if (this._children != null) { for (i = 0; i < 8; i++) { var child = this._children[i]; child.getCollidingWithRay(ray, result, maxDistance); } } } getCollidingWithFrustum(cameraCullInfo, context, customShader, replacementTag, isShadowCasterCull) { this._getCollidingWithFrustum(cameraCullInfo, context, true, customShader, replacementTag, isShadowCasterCull); } isCollidingWithBoundBox(checkBound) { if (!(CollisionUtils.intersectsBoxAndBox(this._bounds, checkBound))) return false; for (var i = 0, n = this._objects.length; i < n; i++) { var object = this._objects[i]; if (CollisionUtils.intersectsBoxAndBox(object.bounds._getBoundBox(), checkBound)) return true; } if (this._children != null) { for (i = 0; i < 8; i++) { var child = this._children[i]; if (child.isCollidingWithBoundBox(checkBound)) return true; } } return false; } isCollidingWithRay(ray, maxDistance = Number.MAX_VALUE) { var distance = CollisionUtils.intersectsRayAndBoxRD(ray, this._bounds); if (distance == -1 || distance > maxDistance) return false; for (var i = 0, n = this._objects.length; i < n; i++) { var object = this._objects[i]; distance = CollisionUtils.intersectsRayAndBoxRD(ray, object.bounds._getBoundBox()); if (distance !== -1 && distance <= maxDistance) return true; } if (this._children != null) { for (i = 0; i < 8; i++) { var child = this._children[i]; if (child.isCollidingWithRay(ray, maxDistance)) return true; } } return false; } getBound() { return this._bounds; } drawAllBounds(debugLine, currentDepth, maxDepth) { if (this._children === null && this._objects.length == 0) return; currentDepth++; var color = BoundsOctreeNode._tempColor0; if (this._isContaion) { color.r = 0.0; color.g = 0.0; color.b = 1.0; } else { var tint = maxDepth ? currentDepth / maxDepth : 0; color.r = 1.0 - tint; color.g = tint; color.b = 0.0; } color.a = 0.3; Utils3D._drawBound(debugLine, this._bounds, color); if (this._children != null) { for (var i = 0; i < 8; i++) { var child = this._children[i]; child && child.drawAllBounds(debugLine, currentDepth, maxDepth); } } } drawAllObjects(debugLine, currentDepth, maxDepth) { currentDepth++; var color = BoundsOctreeNode._tempColor0; if (this._isContaion) { color.r = 0.0; color.g = 0.0; color.b = 1.0; } else { var tint = maxDepth ? currentDepth / maxDepth : 0; color.r = 1.0 - tint; color.g = tint; color.b = 0.0; } color.a = 1.0; for (var i = 0, n = this._objects.length; i < n; i++) Utils3D._drawBound(debugLine, this._objects[i].bounds._getBoundBox(), color); if (this._children != null) { for (i = 0; i < 8; i++) { var child = this._children[i]; child && child.drawAllObjects(debugLine, currentDepth, maxDepth); } } } } BoundsOctreeNode._tempVector3 = new Vector3(); BoundsOctreeNode._tempVector30 = new Vector3(); BoundsOctreeNode._tempVector31 = new Vector3(); BoundsOctreeNode._tempColor0 = new Color(); BoundsOctreeNode._tempBoundBox = new BoundBox(new Vector3(), new Vector3()); BoundsOctreeNode._NUM_OBJECTS_ALLOWED = 8; class OctreeMotionList extends SingletonList { constructor() { super(); } add(element) { var index = element._getIndexInMotionList(); if (index !== -1) throw "OctreeMotionList:element has in PhysicsUpdateList."; this._add(element); element._setIndexInMotionList(this.length++); } remove(element) { var index = element._getIndexInMotionList(); this.length--; if (index !== this.length) { var end = this.elements[this.length]; this.elements[index] = end; end._setIndexInMotionList(index); } element._setIndexInMotionList(-1); } } class BoundsOctree { constructor(initialWorldSize, initialWorldPos, minNodeSize, looseness) { this._motionObjects = new OctreeMotionList(); this.count = 0; if (minNodeSize > initialWorldSize) { console.warn("Minimum node size must be at least as big as the initial world size. Was: " + minNodeSize + " Adjusted to: " + initialWorldSize); minNodeSize = initialWorldSize; } this._initialSize = initialWorldSize; this._minSize = minNodeSize; this._looseness = Math.min(Math.max(looseness, 1.0), 2.0); this._rootNode = new BoundsOctreeNode(this, null, initialWorldSize, initialWorldPos); } _getMaxDepth(node, depth) { depth++; var children = node._children; if (children != null) { var curDepth = depth; for (var i = 0, n = children.length; i < n; i++) { var child = children[i]; child && (depth = Math.max(this._getMaxDepth(child, curDepth), depth)); } } return depth; } _grow(growObjectCenter) { var xDirection = growObjectCenter.x >= 0 ? 1 : -1; var yDirection = growObjectCenter.y >= 0 ? 1 : -1; var zDirection = growObjectCenter.z >= 0 ? 1 : -1; var oldRoot = this._rootNode; var half = this._rootNode.baseLength / 2; var newLength = this._rootNode.baseLength * 2; var rootCenter = this._rootNode.center; var newCenter = new Vector3(rootCenter.x + xDirection * half, rootCenter.y + yDirection * half, rootCenter.z + zDirection * half); this._rootNode = new BoundsOctreeNode(this, null, newLength, newCenter); if (oldRoot.hasAnyObjects()) { var rootPos = this._rootNode._bestFitChild(oldRoot.center); var children = []; for (var i = 0; i < 8; i++) { if (i == rootPos) { oldRoot._parent = this._rootNode; children[i] = oldRoot; } } this._rootNode._children = children; } } add(object) { var count = 0; while (!this._rootNode.add(object)) { var growCenter = BoundsOctree._tempVector30; Vector3.subtract(object.bounds.getCenter(), this._rootNode.center, growCenter); this._grow(growCenter); if (++count > 20) { throw "Aborted Add operation as it seemed to be going on forever (" + (count - 1) + ") attempts at growing the octree."; } } this.count++; } remove(object) { var removed = object._getOctreeNode().remove(object); if (removed) { this.count--; } return removed; } update(object) { var count = 0; var octreeNode = object._getOctreeNode(); if (octreeNode) { while (!octreeNode._update(object)) { var growCenter = BoundsOctree._tempVector30; Vector3.subtract(object.bounds.getCenter(), this._rootNode.center, growCenter); this._grow(growCenter); if (++count > 20) { throw "Aborted Add operation as it seemed to be going on forever (" + (count - 1) + ") attempts at growing the octree."; } } return true; } else { return false; } } shrinkRootIfPossible() { this._rootNode = this._rootNode.shrinkIfPossible(this._initialSize); } addMotionObject(object) { this._motionObjects.add(object); } removeMotionObject(object) { this._motionObjects.remove(object); } updateMotionObjects() { var elements = this._motionObjects.elements; for (var i = 0, n = this._motionObjects.length; i < n; i++) { var object = elements[i]; this.update(object); object._setIndexInMotionList(-1); } this._motionObjects.length = 0; } isCollidingWithBoundBox(checkBounds) { return this._rootNode.isCollidingWithBoundBox(checkBounds); } isCollidingWithRay(ray, maxDistance = Number.MAX_VALUE) { return this._rootNode.isCollidingWithRay(ray, maxDistance); } getCollidingWithBoundBox(checkBound, result) { this._rootNode.getCollidingWithBoundBox(checkBound, result); } getCollidingWithRay(ray, result, maxDistance = Number.MAX_VALUE) { this._rootNode.getCollidingWithRay(ray, result, maxDistance); } getCollidingWithFrustum(cameraCullInfo, context, shader, replacementTag, isShadowCasterCull) { this._rootNode.getCollidingWithFrustum(cameraCullInfo, context, shader, replacementTag, isShadowCasterCull); } getMaxBounds() { return this._rootNode.getBound(); } drawAllBounds(pixelLine) { var maxDepth = this._getMaxDepth(this._rootNode, -1); this._rootNode.drawAllBounds(pixelLine, -1, maxDepth); } drawAllObjects(pixelLine) { var maxDepth = this._getMaxDepth(this._rootNode, -1); this._rootNode.drawAllObjects(pixelLine, -1, maxDepth); } } BoundsOctree._tempVector30 = new Vector3(); class Lightmap { } class BoundSphere { constructor(center, radius) { this.center = center; this.radius = radius; } toDefault() { this.center.toDefault(); this.radius = 0; } static createFromSubPoints(points, start, count, out) { if (points == null) { throw new Error("points"); } if (start < 0 || start >= points.length) { throw new Error("start" + start + "Must be in the range [0, " + (points.length - 1) + "]"); } if (count < 0 || (start + count) > points.length) { throw new Error("count" + count + "Must be in the range <= " + points.length + "}"); } var upperEnd = start + count; var center = BoundSphere._tempVector3; center.x = 0; center.y = 0; center.z = 0; for (var i = start; i < upperEnd; ++i) { Vector3.add(points[i], center, center); } var outCenter = out.center; Vector3.scale(center, 1 / count, outCenter); var radius = 0.0; for (i = start; i < upperEnd; ++i) { var distance = Vector3.distanceSquared(outCenter, points[i]); if (distance > radius) radius = distance; } out.radius = Math.sqrt(radius); } static createfromPoints(points, out) { if (points == null) { throw new Error("points"); } BoundSphere.createFromSubPoints(points, 0, points.length, out); } intersectsRayDistance(ray) { return CollisionUtils.intersectsRayAndSphereRD(ray, this); } intersectsRayPoint(ray, outPoint) { return CollisionUtils.intersectsRayAndSphereRP(ray, this, outPoint); } cloneTo(destObject) { var dest = destObject; this.center.cloneTo(dest.center); dest.radius = this.radius; } clone() { var dest = new BoundSphere(new Vector3(), 0); this.cloneTo(dest); return dest; } } BoundSphere._tempVector3 = new Vector3(); class ShadowSliceData { constructor() { this.cameraShaderValue = new ShaderData(); this.position = new Vector3(); this.viewMatrix = new Matrix4x4(); this.projectionMatrix = new Matrix4x4(); this.viewProjectMatrix = new Matrix4x4(); this.cullPlanes = [new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3())]; this.splitBoundSphere = new BoundSphere(new Vector3(), 0.0); } } class ShadowSpotData { constructor() { this.cameraShaderValue = new ShaderData(); this.position = new Vector3; this.viewMatrix = new Matrix4x4(); this.projectionMatrix = new Matrix4x4(); this.viewProjectMatrix = new Matrix4x4(); this.cameraCullInfo = new CameraCullInfo(); } } (function (ShadowLightType) { ShadowLightType[ShadowLightType["DirectionLight"] = 0] = "DirectionLight"; ShadowLightType[ShadowLightType["SpotLight"] = 1] = "SpotLight"; ShadowLightType[ShadowLightType["PointLight"] = 2] = "PointLight"; })(exports.ShadowLightType || (exports.ShadowLightType = {})); class ShadowCasterPass { constructor() { this._shadowBias = new Vector4(); this._shadowParams = new Vector4(); this._shadowMapSize = new Vector4(); this._shadowMatrices = new Float32Array(16 * (ShadowCasterPass._maxCascades)); this._shadowSpotMatrices = new Matrix4x4(); this._splitBoundSpheres = new Float32Array(ShadowCasterPass._maxCascades * 4); this._cascadeCount = 0; this._shadowMapWidth = 0; this._shadowMapHeight = 0; this._shadowSliceDatas = [new ShadowSliceData(), new ShadowSliceData(), new ShadowSliceData(), new ShadowSliceData()]; this._shadowSpotData = new ShadowSpotData(); this._lightUp = new Vector3(); this._lightSide = new Vector3(); this._lightForward = new Vector3(); this._shadowSpotData.cameraCullInfo.boundFrustum = new BoundFrustum(new Matrix4x4()); } _setupShadowCasterShaderValues(context, shaderValues, shadowSliceData, LightParam, shadowparams, shadowBias, lightType) { shaderValues.setVector(ShadowCasterPass.SHADOW_BIAS, shadowBias); switch (lightType) { case exports.LightType.Directional: shaderValues.setVector3(ShadowCasterPass.SHADOW_LIGHT_DIRECTION, LightParam); break; case exports.LightType.Spot: shaderValues.setVector(ShadowCasterPass.SHADOW_PARAMS, shadowparams); break; case exports.LightType.Point: break; } var cameraSV = shadowSliceData.cameraShaderValue; cameraSV.setMatrix4x4(BaseCamera.VIEWMATRIX, shadowSliceData.viewMatrix); cameraSV.setMatrix4x4(BaseCamera.PROJECTMATRIX, shadowSliceData.projectionMatrix); cameraSV.setMatrix4x4(BaseCamera.VIEWPROJECTMATRIX, shadowSliceData.viewProjectMatrix); context.viewMatrix = shadowSliceData.viewMatrix; context.projectionMatrix = shadowSliceData.projectionMatrix; context.projectionViewMatrix = shadowSliceData.viewProjectMatrix; } _setupShadowReceiverShaderValues(shaderValues) { var light = this._light; if (light.shadowCascadesMode !== exports.ShadowCascadesMode.NoCascades) shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_CASCADE); else shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_CASCADE); switch (light.shadowMode) { case exports.ShadowMode.Hard: shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SOFT_SHADOW_LOW); shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SOFT_SHADOW_HIGH); break; case exports.ShadowMode.SoftLow: shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SOFT_SHADOW_LOW); shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SOFT_SHADOW_HIGH); break; case exports.ShadowMode.SoftHigh: shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SOFT_SHADOW_HIGH); shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SOFT_SHADOW_LOW); break; } shaderValues.setTexture(ShadowCasterPass.SHADOW_MAP, this._shadowDirectLightMap); shaderValues.setBuffer(ShadowCasterPass.SHADOW_MATRICES, this._shadowMatrices); shaderValues.setVector(ShadowCasterPass.SHADOW_MAP_SIZE, this._shadowMapSize); shaderValues.setVector(ShadowCasterPass.SHADOW_PARAMS, this._shadowParams); shaderValues.setBuffer(ShadowCasterPass.SHADOW_SPLIT_SPHERES, this._splitBoundSpheres); } _setupSpotShadowReceiverShaderValues(shaderValues) { var spotLight = this._light; switch (spotLight.shadowMode) { case exports.ShadowMode.Hard: shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT_SOFT_SHADOW_HIGH); shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT_SOFT_SHADOW_LOW); break; case exports.ShadowMode.SoftLow: shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT_SOFT_SHADOW_LOW); shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT_SOFT_SHADOW_HIGH); break; case exports.ShadowMode.SoftHigh: shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT_SOFT_SHADOW_HIGH); shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT_SOFT_SHADOW_LOW); break; } shaderValues.setTexture(ShadowCasterPass.SHADOW_SPOTMAP, this._shadowSpotLightMap); shaderValues.setMatrix4x4(ShadowCasterPass.SHADOW_SPOTMATRICES, this._shadowSpotMatrices); shaderValues.setVector(ShadowCasterPass.SHADOW_MAP_SIZE, this._shadowMapSize); shaderValues.setVector(ShadowCasterPass.SHADOW_PARAMS, this._shadowParams); } update(camera, light, lightType) { switch (lightType) { case exports.ShadowLightType.DirectionLight: this._light = light; var lightWorld = ShadowCasterPass._tempMatrix0; var lightWorldE = lightWorld.elements; var lightUp = this._lightUp; var lightSide = this._lightSide; var lightForward = this._lightForward; Matrix4x4.createFromQuaternion(light._transform.rotation, lightWorld); lightSide.setValue(lightWorldE[0], lightWorldE[1], lightWorldE[2]); lightUp.setValue(lightWorldE[4], lightWorldE[5], lightWorldE[6]); lightForward.setValue(-lightWorldE[8], -lightWorldE[9], -lightWorldE[10]); var atlasResolution = light._shadowResolution; var cascadesMode = light._shadowCascadesMode; var cascadesCount; var shadowTileResolution; var shadowMapWidth, shadowMapHeight; if (cascadesMode == exports.ShadowCascadesMode.NoCascades) { cascadesCount = 1; shadowTileResolution = atlasResolution; shadowMapWidth = atlasResolution; shadowMapHeight = atlasResolution; } else { cascadesCount = cascadesMode == exports.ShadowCascadesMode.TwoCascades ? 2 : 4; shadowTileResolution = ShadowUtils.getMaxTileResolutionInAtlas(atlasResolution, atlasResolution, cascadesCount); shadowMapWidth = shadowTileResolution * 2; shadowMapHeight = cascadesMode == exports.ShadowCascadesMode.TwoCascades ? shadowTileResolution : shadowTileResolution * 2; } this._cascadeCount = cascadesCount; this._shadowMapWidth = shadowMapWidth; this._shadowMapHeight = shadowMapHeight; var splitDistance = ShadowCasterPass._cascadesSplitDistance; var frustumPlanes = ShadowCasterPass._frustumPlanes; var cameraNear = camera.nearPlane; var shadowFar = Math.min(camera.farPlane, light._shadowDistance); var shadowMatrices = this._shadowMatrices; var boundSpheres = this._splitBoundSpheres; ShadowUtils.getCascadesSplitDistance(light._shadowTwoCascadeSplits, light._shadowFourCascadeSplits, cameraNear, shadowFar, camera.fieldOfView * MathUtils3D.Deg2Rad, camera.aspectRatio, cascadesMode, splitDistance); ShadowUtils.getCameraFrustumPlanes(camera.projectionViewMatrix, frustumPlanes); var forward = ShadowCasterPass._tempVector30; camera._transform.getForward(forward); Vector3.normalize(forward, forward); for (var i = 0; i < cascadesCount; i++) { var sliceData = this._shadowSliceDatas[i]; sliceData.sphereCenterZ = ShadowUtils.getBoundSphereByFrustum(splitDistance[i], splitDistance[i + 1], camera.fieldOfView * MathUtils3D.Deg2Rad, camera.aspectRatio, camera._transform.position, forward, sliceData.splitBoundSphere); ShadowUtils.getDirectionLightShadowCullPlanes(frustumPlanes, i, splitDistance, cameraNear, lightForward, sliceData); ShadowUtils.getDirectionalLightMatrices(lightUp, lightSide, lightForward, i, light._shadowNearPlane, shadowTileResolution, sliceData, shadowMatrices); if (cascadesCount > 1) ShadowUtils.applySliceTransform(sliceData, shadowMapWidth, shadowMapHeight, i, shadowMatrices); } ShadowUtils.prepareShadowReceiverShaderValues(light, shadowMapWidth, shadowMapHeight, this._shadowSliceDatas, cascadesCount, this._shadowMapSize, this._shadowParams, shadowMatrices, boundSpheres); break; case exports.ShadowLightType.SpotLight: this._light = light; var lightWorld = ShadowCasterPass._tempMatrix0; var lightForward = this._lightForward; var shadowResolution = this._light._shadowResolution; this._shadowMapWidth = shadowResolution; this._shadowMapHeight = shadowResolution; var shadowSpotData = this._shadowSpotData; ShadowUtils.getSpotLightShadowData(shadowSpotData, this._light, shadowResolution, this._shadowParams, this._shadowSpotMatrices, this._shadowMapSize); break; case exports.ShadowLightType.PointLight: break; default: throw ("There is no shadow of this type"); break; } } render(context, scene, lightType) { switch (lightType) { case exports.ShadowLightType.DirectionLight: var shaderValues = scene._shaderValues; context.pipelineMode = "ShadowCaster"; ShaderData.setRuntimeValueMode(false); var shadowMap = this._shadowDirectLightMap = ShadowUtils.getTemporaryShadowTexture(this._shadowMapWidth, this._shadowMapHeight, Laya.RenderTextureDepthFormat.DEPTH_16); shadowMap._start(); var light = this._light; for (var i = 0, n = this._cascadeCount; i < n; i++) { var sliceData = this._shadowSliceDatas[i]; ShadowUtils.getShadowBias(light, sliceData.projectionMatrix, sliceData.resolution, this._shadowBias); this._setupShadowCasterShaderValues(context, shaderValues, sliceData, this._lightForward, this._shadowParams, this._shadowBias, exports.LightType.Directional); var shadowCullInfo = FrustumCulling._shadowCullInfo; shadowCullInfo.position = sliceData.position; shadowCullInfo.cullPlanes = sliceData.cullPlanes; shadowCullInfo.cullPlaneCount = sliceData.cullPlaneCount; shadowCullInfo.cullSphere = sliceData.splitBoundSphere; shadowCullInfo.direction = this._lightForward; var needRender = FrustumCulling.cullingShadow(shadowCullInfo, scene, context); context.cameraShaderValue = sliceData.cameraShaderValue; Camera._updateMark++; var gl = Laya.LayaGL.instance; var resolution = sliceData.resolution; var offsetX = sliceData.offsetX; var offsetY = sliceData.offsetY; gl.enable(gl.SCISSOR_TEST); gl.viewport(offsetX, offsetY, resolution, resolution); gl.scissor(offsetX, offsetY, resolution, resolution); gl.clear(gl.DEPTH_BUFFER_BIT); if (needRender) { gl.scissor(offsetX + 1, offsetY + 1, resolution - 2, resolution - 2); scene._opaqueQueue._render(context); } } shadowMap._end(); this._setupShadowReceiverShaderValues(shaderValues); ShaderData.setRuntimeValueMode(true); context.pipelineMode = "Forward"; break; case exports.ShadowLightType.SpotLight: var shaderValues = scene._shaderValues; context.pipelineMode = "ShadowCaster"; ShaderData.setRuntimeValueMode(false); var spotlight = this._light; var shadowMap = this._shadowSpotLightMap = ShadowUtils.getTemporaryShadowTexture(this._shadowMapWidth, this._shadowMapHeight, Laya.RenderTextureDepthFormat.DEPTH_16); shadowMap._start(); var shadowSpotData = this._shadowSpotData; ShadowUtils.getShadowBias(spotlight, shadowSpotData.projectionMatrix, shadowSpotData.resolution, this._shadowBias); this._setupShadowCasterShaderValues(context, shaderValues, shadowSpotData, this._light.transform.position, this._shadowParams, this._shadowBias, exports.LightType.Spot); var needRender = FrustumCulling.cullingSpotShadow(shadowSpotData.cameraCullInfo, scene, context); context.cameraShaderValue = shadowSpotData.cameraShaderValue; Camera._updateMark++; var gl = Laya.LayaGL.instance; gl.enable(gl.SCISSOR_TEST); gl.viewport(shadowSpotData.offsetX, shadowSpotData.offsetY, shadowSpotData.resolution, shadowSpotData.resolution); gl.scissor(shadowSpotData.offsetX, shadowSpotData.offsetY, shadowSpotData.resolution, shadowSpotData.resolution); gl.clear(gl.DEPTH_BUFFER_BIT); if (needRender) { gl.scissor(shadowSpotData.offsetX, shadowSpotData.offsetY, shadowSpotData.resolution, shadowSpotData.resolution); scene._opaqueQueue._render(context); } shadowMap._end(); this._setupSpotShadowReceiverShaderValues(shaderValues); ShaderData.setRuntimeValueMode(true); context.pipelineMode = "Forward"; break; case exports.ShadowLightType.PointLight: break; default: throw ("There is no shadow of this type"); break; } } cleanUp() { this._shadowDirectLightMap && RenderTexture.recoverToPool(this._shadowDirectLightMap); this._shadowSpotLightMap && RenderTexture.recoverToPool(this._shadowSpotLightMap); this._shadowDirectLightMap = null; this._shadowSpotLightMap = null; this._light = null; } } ShadowCasterPass._tempVector30 = new Vector3(); ShadowCasterPass._tempMatrix0 = new Matrix4x4(); ShadowCasterPass.SHADOW_BIAS = Shader3D.propertyNameToID("u_ShadowBias"); ShadowCasterPass.SHADOW_LIGHT_DIRECTION = Shader3D.propertyNameToID("u_ShadowLightDirection"); ShadowCasterPass.SHADOW_SPLIT_SPHERES = Shader3D.propertyNameToID("u_ShadowSplitSpheres"); ShadowCasterPass.SHADOW_MATRICES = Shader3D.propertyNameToID("u_ShadowMatrices"); ShadowCasterPass.SHADOW_MAP_SIZE = Shader3D.propertyNameToID("u_ShadowMapSize"); ShadowCasterPass.SHADOW_MAP = Shader3D.propertyNameToID("u_ShadowMap"); ShadowCasterPass.SHADOW_PARAMS = Shader3D.propertyNameToID("u_ShadowParams"); ShadowCasterPass.SHADOW_SPOTMAP = Shader3D.propertyNameToID("u_SpotShadowMap"); ShadowCasterPass.SHADOW_SPOTMATRICES = Shader3D.propertyNameToID("u_SpotViewProjectMatrix"); ShadowCasterPass._maxCascades = 4; ShadowCasterPass._cascadesSplitDistance = new Array(ShadowCasterPass._maxCascades + 1); ShadowCasterPass._frustumPlanes = new Array(new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3()), new Plane(new Vector3())); class DynamicBatchManager { constructor() { this._batchRenderElementPool = []; } static _registerManager(manager) { DynamicBatchManager._managers.push(manager); } _clear() { this._batchRenderElementPoolIndex = 0; } _getBatchRenderElementFromPool() { throw "StaticBatch:must override this function."; } dispose() { } } DynamicBatchManager._managers = []; (function (AmbientMode) { AmbientMode[AmbientMode["SolidColor"] = 0] = "SolidColor"; AmbientMode[AmbientMode["SphericalHarmonics"] = 1] = "SphericalHarmonics"; })(exports.AmbientMode || (exports.AmbientMode = {})); class Scene3D extends Laya.Sprite { constructor() { super(); this._lightCount = 0; this._pointLights = new LightQueue(); this._spotLights = new LightQueue(); this._directionLights = new LightQueue(); this._alternateLights = new AlternateLightQueue(); this._lightmaps = []; this._skyRenderer = new SkyRenderer(); this._input = new Input3D(); this._timer = Laya.ILaya.timer; this._time = 0; this._shCoefficients = new Array(7); this._ambientMode = exports.AmbientMode.SolidColor; this._ambientSphericalHarmonics = new SphericalHarmonicsL2(); this._ambientSphericalHarmonicsIntensity = 1.0; this._reflectionDecodeFormat = Laya.TextureDecodeFormat.Normal; this._reflectionIntensity = 1.0; this._collsionTestList = []; this._renders = new SimpleSingletonList(); this._opaqueQueue = new RenderQueue(false); this._transparentQueue = new RenderQueue(true); this._cameraPool = []; this._animatorPool = new SimpleSingletonList(); this._scriptPool = new Array(); this._tempScriptPool = new Array(); this._needClearScriptPool = false; this._reflectionCubeHDRParams = new Vector4(); this.currentCreationLayer = Math.pow(2, 0); this.enableLight = true; this._key = new Laya.SubmitKey(); this._pickIdToSprite = new Object(); this._reflectionMode = 0; if (!Config3D._config.isUseCannonPhysicsEngine && Physics3D._bullet) this._physicsSimulation = new PhysicsSimulation(Scene3D.physicsSettings); else if (Physics3D._cannon) { this._cannonPhysicsSimulation = new Laya.CannonPhysicsSimulation(Scene3D.cannonPhysicsSettings); } this._shaderValues = new ShaderData(null); this.enableFog = false; this.fogStart = 300; this.fogRange = 1000; this.fogColor = new Vector3(0.7, 0.7, 0.7); this.ambientColor = new Vector3(0.212, 0.227, 0.259); this.reflectionIntensity = 1.0; this.reflection = TextureCube.blackTexture; for (var i = 0; i < 7; i++) this._shCoefficients[i] = new Vector4(); this._shaderValues.setVector(Scene3D.REFLECTIONCUBE_HDR_PARAMS, this._reflectionCubeHDRParams); if (Laya.Render.supportWebGLPlusCulling) { this._cullingBufferIndices = new Int32Array(1024); this._cullingBufferResult = new Int32Array(1024); } this._scene = this; this._input.__init__(Laya.Render.canvas, this); if (Scene3D.octreeCulling) this._octree = new BoundsOctree(Scene3D.octreeInitialSize, Scene3D.octreeInitialCenter, Scene3D.octreeMinNodeSize, Scene3D.octreeLooseness); if (FrustumCulling.debugFrustumCulling) { this._debugTool = new PixelLineSprite3D(); var lineMaterial = new PixelLineMaterial(); lineMaterial.renderQueue = Material.RENDERQUEUE_TRANSPARENT; lineMaterial.alphaTest = false; lineMaterial.depthWrite = false; lineMaterial.cull = RenderState.CULL_BACK; lineMaterial.blend = RenderState.BLEND_ENABLE_ALL; lineMaterial.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; lineMaterial.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; lineMaterial.depthTest = RenderState.DEPTHTEST_LESS; this._debugTool.pixelLineRenderer.sharedMaterial = lineMaterial; } } static __init__() { var con = Config3D._config; var multiLighting = con._multiLighting; if (multiLighting) { const width = 4; var maxLightCount = con.maxLightCount; var clusterSlices = con.lightClusterCount; Cluster.instance = new Cluster(clusterSlices.x, clusterSlices.y, clusterSlices.z, Math.min(con.maxLightCount, con._maxAreaLightCountPerClusterAverage)); Scene3D._lightTexture = Utils3D._createFloatTextureBuffer(width, maxLightCount); Scene3D._lightTexture.lock = true; Scene3D._lightPixles = new Float32Array(maxLightCount * width * 4); } Scene3DShaderDeclaration.SHADERDEFINE_FOG = Shader3D.getDefineByName("FOG"); Scene3DShaderDeclaration.SHADERDEFINE_DIRECTIONLIGHT = Shader3D.getDefineByName("DIRECTIONLIGHT"); Scene3DShaderDeclaration.SHADERDEFINE_POINTLIGHT = Shader3D.getDefineByName("POINTLIGHT"); Scene3DShaderDeclaration.SHADERDEFINE_SPOTLIGHT = Shader3D.getDefineByName("SPOTLIGHT"); Scene3DShaderDeclaration.SHADERDEFINE_SHADOW = Shader3D.getDefineByName("SHADOW"); Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_CASCADE = Shader3D.getDefineByName("SHADOW_CASCADE"); Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SOFT_SHADOW_LOW = Shader3D.getDefineByName("SHADOW_SOFT_SHADOW_LOW"); Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SOFT_SHADOW_HIGH = Shader3D.getDefineByName("SHADOW_SOFT_SHADOW_HIGH"); Scene3DShaderDeclaration.SHADERDEFINE_GI_AMBIENT_SH = Shader3D.getDefineByName("GI_AMBIENT_SH"); Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT = Shader3D.getDefineByName("SHADOW_SPOT"); Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT_SOFT_SHADOW_LOW = Shader3D.getDefineByName("SHADOW_SPOT_SOFT_SHADOW_LOW"); Scene3DShaderDeclaration.SHADERDEFINE_SHADOW_SPOT_SOFT_SHADOW_HIGH = Shader3D.getDefineByName("SHADOW_SPOT_SOFT_SHADOW_HIGH"); var config = Config3D._config; var configShaderValue = Scene3D._configDefineValues; (config._multiLighting) || (configShaderValue.add(Shader3D.SHADERDEFINE_LEGACYSINGALLIGHTING)); if (Laya.LayaGL.layaGPUInstance._isWebGL2) configShaderValue.add(Shader3D.SHADERDEFINE_GRAPHICS_API_GLES3); else configShaderValue.add(Shader3D.SHADERDEFINE_GRAPHICS_API_GLES2); switch (config.pbrRenderQuality) { case exports.PBRRenderQuality.High: configShaderValue.add(PBRMaterial.SHADERDEFINE_LAYA_PBR_BRDF_HIGH); break; case exports.PBRRenderQuality.Low: configShaderValue.add(PBRMaterial.SHADERDEFINE_LAYA_PBR_BRDF_LOW); break; default: throw "Scene3D:unknown shader quality."; } if (config.isUseCannonPhysicsEngine) { Scene3D.cannonPhysicsSettings = new Laya.CannonPhysicsSettings(); } else { Scene3D.physicsSettings = new PhysicsSettings(); } } static load(url, complete) { Laya.ILaya.loader.create(url, complete, null, Scene3D.HIERARCHY); } get url() { return this._url; } get enableFog() { return this._enableFog; } set enableFog(value) { if (this._enableFog !== value) { this._enableFog = value; if (value) { this._shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_FOG); } else this._shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_FOG); } } get fogColor() { return this._shaderValues.getVector3(Scene3D.FOGCOLOR); } set fogColor(value) { this._shaderValues.setVector3(Scene3D.FOGCOLOR, value); } get fogStart() { return this._shaderValues.getNumber(Scene3D.FOGSTART); } set fogStart(value) { this._shaderValues.setNumber(Scene3D.FOGSTART, value); } get fogRange() { return this._shaderValues.getNumber(Scene3D.FOGRANGE); } set fogRange(value) { this._shaderValues.setNumber(Scene3D.FOGRANGE, value); } get ambientMode() { return this._ambientMode; } set ambientMode(value) { if (this._ambientMode !== value) { switch (value) { case exports.AmbientMode.SolidColor: this._shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_GI_AMBIENT_SH); break; case exports.AmbientMode.SphericalHarmonics: this._shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_GI_AMBIENT_SH); break; default: throw "Scene3D: unknown ambientMode."; } this._ambientMode = value; } } get ambientColor() { return this._shaderValues.getVector3(Scene3D.AMBIENTCOLOR); } set ambientColor(value) { this._shaderValues.setVector3(Scene3D.AMBIENTCOLOR, value); } get ambientSphericalHarmonics() { return this._ambientSphericalHarmonics; } set ambientSphericalHarmonics(value) { var originalSH = value || SphericalHarmonicsL2._default; this._applySHCoefficients(originalSH, Math.pow(this._ambientSphericalHarmonicsIntensity, 2.2)); if (this._ambientSphericalHarmonics != value) value.cloneTo(this._ambientSphericalHarmonics); } get ambientSphericalHarmonicsIntensity() { return this._ambientSphericalHarmonicsIntensity; } set ambientSphericalHarmonicsIntensity(value) { value = Math.max(Math.min(value, 8.0), 0.0); if (this._ambientSphericalHarmonicsIntensity !== value) { var originalSH = this._ambientSphericalHarmonics || SphericalHarmonicsL2._default; this._applySHCoefficients(originalSH, Math.pow(value, 2.2)); this._ambientSphericalHarmonicsIntensity = value; } } get reflection() { return this._reflection; } set reflection(value) { if (this._reflection != value) { this._shaderValues.setTexture(Scene3D.REFLECTIONTEXTURE, value || TextureCube.blackTexture); this._reflection = value; } } get reflectionDecodingFormat() { return this._reflectionDecodeFormat; } set reflectionDecodingFormat(value) { if (this._reflectionDecodeFormat != value) { this._reflectionCubeHDRParams.x = this._reflectionIntensity; if (this._reflectionDecodeFormat == Laya.TextureDecodeFormat.RGBM) this._reflectionCubeHDRParams.x *= 5.0; this._reflectionDecodeFormat = value; } } get reflectionIntensity() { return this._reflectionIntensity; } set reflectionIntensity(value) { value = Math.max(Math.min(value, 1.0), 0.0); this._reflectionCubeHDRParams.x = value; if (this._reflectionDecodeFormat == Laya.TextureDecodeFormat.RGBM) this._reflectionCubeHDRParams.x *= 5.0; this._reflectionIntensity = value; } get skyRenderer() { return this._skyRenderer; } get physicsSimulation() { return this._physicsSimulation; } get cannonPhysicsSimulation() { return this._cannonPhysicsSimulation; } get timer() { return this._timer; } set timer(value) { this._timer = value; } get input() { return this._input; } get lightmaps() { return this._lightmaps.slice(); } set lightmaps(value) { var maps = this._lightmaps; if (maps) { for (var i = 0, n = maps.length; i < n; i++) { var map = maps[i]; map.lightmapColor._removeReference(); map.lightmapDirection._removeReference(); } } if (value) { var count = value.length; maps.length = count; for (i = 0; i < count; i++) { var map = value[i]; map.lightmapColor && map.lightmapColor._addReference(); map.lightmapDirection && map.lightmapDirection._addReference(); maps[i] = map; } } else { maps.length = 0; } } _applySHCoefficients(originalSH, intensity) { var optSH = this._shCoefficients; for (var i = 0; i < 3; i++) { var shaderSHA = optSH[i]; var shaderSHB = optSH[i + 3]; shaderSHA.setValue(originalSH.getCoefficient(i, 3) * intensity, originalSH.getCoefficient(i, 1) * intensity, originalSH.getCoefficient(i, 2) * intensity, (originalSH.getCoefficient(i, 0) - originalSH.getCoefficient(i, 6)) * intensity); shaderSHB.setValue(originalSH.getCoefficient(i, 4) * intensity, originalSH.getCoefficient(i, 5) * intensity, originalSH.getCoefficient(i, 6) * 3 * intensity, originalSH.getCoefficient(i, 7) * intensity); } optSH[6].setValue(originalSH.getCoefficient(0, 8) * intensity, originalSH.getCoefficient(1, 8) * intensity, originalSH.getCoefficient(2, 8) * intensity, 1); var shaderValues = this._shaderValues; shaderValues.setVector(Scene3D.AMBIENTSHAR, optSH[0]); shaderValues.setVector(Scene3D.AMBIENTSHAG, optSH[1]); shaderValues.setVector(Scene3D.AMBIENTSHAB, optSH[2]); shaderValues.setVector(Scene3D.AMBIENTSHBR, optSH[3]); shaderValues.setVector(Scene3D.AMBIENTSHBG, optSH[4]); shaderValues.setVector(Scene3D.AMBIENTSHBB, optSH[5]); shaderValues.setVector(Scene3D.AMBIENTSHC, optSH[6]); } _update() { var delta = this.timer._delta / 1000; this._time += delta; this._shaderValues.setNumber(Scene3D.TIME, this._time); var simulation = this._physicsSimulation; if (Physics3D._enablePhysics && !PhysicsSimulation.disableSimulation && !Config3D._config.isUseCannonPhysicsEngine) { simulation._updatePhysicsTransformFromRender(); PhysicsComponent._addUpdateList = false; simulation._simulate(delta); simulation._updateCharacters(); PhysicsComponent._addUpdateList = true; simulation._updateCollisions(); simulation._eventScripts(); } if (Physics3D._cannon && Config3D._config.isUseCannonPhysicsEngine) { var cannonSimulation = this._cannonPhysicsSimulation; cannonSimulation._updatePhysicsTransformFromRender(); Laya.CannonPhysicsComponent._addUpdateList = false; cannonSimulation._simulate(delta); Laya.CannonPhysicsComponent._addUpdateList = true; cannonSimulation._updateCollisions(); cannonSimulation._eventScripts(); } this._input._update(); this._clearScript(); this._updateScript(); Animator._update(this); this._lateUpdateScript(); } _binarySearchIndexInCameraPool(camera) { var start = 0; var end = this._cameraPool.length - 1; var mid; while (start <= end) { mid = Math.floor((start + end) / 2); var midValue = this._cameraPool[mid]._renderingOrder; if (midValue == camera._renderingOrder) return mid; else if (midValue > camera._renderingOrder) end = mid - 1; else start = mid + 1; } return start; } _allotPickColorByID(id, pickColor) { var pickColorR = Math.floor(id / (255 * 255)); id -= pickColorR * 255 * 255; var pickColorG = Math.floor(id / 255); id -= pickColorG * 255; var pickColorB = id; pickColor.x = pickColorR / 255; pickColor.y = pickColorG / 255; pickColor.z = pickColorB / 255; pickColor.w = 1.0; } _searchIDByPickColor(pickColor) { var id = pickColor.x * 255 * 255 + pickColor.y * 255 + pickColor.z; return id; } onEnable() { this._input._onCanvasEvent(Laya.Render.canvas); } onDisable() { this._input._offCanvasEvent(Laya.Render.canvas); } _setCreateURL(url) { this._url = Laya.URL.formatURL(url); } _getGroup() { return this._group; } _setGroup(value) { this._group = value; } _clearScript() { if (this._needClearScriptPool) { var scripts = this._scriptPool; for (var i = 0, n = scripts.length; i < n; i++) { var script = scripts[i]; if (script) { script._indexInPool = this._tempScriptPool.length; this._tempScriptPool.push(script); } } this._scriptPool = this._tempScriptPool; scripts.length = 0; this._tempScriptPool = scripts; this._needClearScriptPool = false; } } _updateScript() { var scripts = this._scriptPool; for (var i = 0, n = scripts.length; i < n; i++) { var script = scripts[i]; (script && script.enabled) && (script.onUpdate()); } } _lateUpdateScript() { var scripts = this._scriptPool; for (var i = 0, n = scripts.length; i < n; i++) { var script = scripts[i]; (script && script.enabled) && (script.onLateUpdate()); } } _onActive() { super._onActive(); Laya.ILaya.stage._scene3Ds.push(this); } _onInActive() { super._onInActive(); var scenes = Laya.ILaya.stage._scene3Ds; scenes.splice(scenes.indexOf(this), 1); } _prepareSceneToRender() { var shaderValues = this._shaderValues; var multiLighting = Config3D._config._multiLighting; if (multiLighting) { var ligTex = Scene3D._lightTexture; var ligPix = Scene3D._lightPixles; const pixelWidth = ligTex.width; const floatWidth = pixelWidth * 4; var curCount = 0; var dirCount = this._directionLights._length; var dirElements = this._directionLights._elements; if (dirCount > 0) { var sunLightIndex = this._directionLights.getBrightestLight(); this._mainDirectionLight = dirElements[sunLightIndex]; this._directionLights.normalLightOrdering(sunLightIndex); for (var i = 0; i < dirCount; i++, curCount++) { var dirLight = dirElements[i]; var dir = dirLight._direction; var intCor = dirLight._intensityColor; var off = floatWidth * curCount; Vector3.scale(dirLight.color, dirLight._intensity, intCor); dirLight.transform.worldMatrix.getForward(dir); Vector3.normalize(dir, dir); ligPix[off] = intCor.x; ligPix[off + 1] = intCor.y; ligPix[off + 2] = intCor.z; ligPix[off + 4] = dir.x; ligPix[off + 5] = dir.y; ligPix[off + 6] = dir.z; if (i == 0) { shaderValues.setVector3(Scene3D.SUNLIGHTDIRCOLOR, intCor); shaderValues.setVector3(Scene3D.SUNLIGHTDIRECTION, dir); } } shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_DIRECTIONLIGHT); } else { shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_DIRECTIONLIGHT); } var poiCount = this._pointLights._length; if (poiCount > 0) { var poiElements = this._pointLights._elements; var mainPointLightIndex = this._pointLights.getBrightestLight(); this._mainPointLight = poiElements[mainPointLightIndex]; this._pointLights.normalLightOrdering(mainPointLightIndex); for (var i = 0; i < poiCount; i++, curCount++) { var poiLight = poiElements[i]; var pos = poiLight.transform.position; var intCor = poiLight._intensityColor; var off = floatWidth * curCount; Vector3.scale(poiLight.color, poiLight._intensity, intCor); ligPix[off] = intCor.x; ligPix[off + 1] = intCor.y; ligPix[off + 2] = intCor.z; ligPix[off + 3] = poiLight.range; ligPix[off + 4] = pos.x; ligPix[off + 5] = pos.y; ligPix[off + 6] = pos.z; } shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_POINTLIGHT); } else { shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_POINTLIGHT); } var spoCount = this._spotLights._length; if (spoCount > 0) { var spoElements = this._spotLights._elements; var mainSpotLightIndex = this._spotLights.getBrightestLight(); this._mainSpotLight = spoElements[mainSpotLightIndex]; this._spotLights.normalLightOrdering(mainSpotLightIndex); for (var i = 0; i < spoCount; i++, curCount++) { var spoLight = spoElements[i]; var dir = spoLight._direction; var pos = spoLight.transform.position; var intCor = spoLight._intensityColor; var off = floatWidth * curCount; Vector3.scale(spoLight.color, spoLight._intensity, intCor); spoLight.transform.worldMatrix.getForward(dir); Vector3.normalize(dir, dir); ligPix[off] = intCor.x; ligPix[off + 1] = intCor.y; ligPix[off + 2] = intCor.z; ligPix[off + 3] = spoLight.range; ligPix[off + 4] = pos.x; ligPix[off + 5] = pos.y; ligPix[off + 6] = pos.z; ligPix[off + 7] = spoLight.spotAngle * Math.PI / 180; ligPix[off + 8] = dir.x; ligPix[off + 9] = dir.y; ligPix[off + 10] = dir.z; } shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SPOTLIGHT); } else { shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SPOTLIGHT); } (curCount > 0) && (ligTex.setSubPixels(0, 0, pixelWidth, curCount, ligPix, 0)); shaderValues.setTexture(Scene3D.LIGHTBUFFER, ligTex); shaderValues.setInt(Scene3D.DIRECTIONLIGHTCOUNT, this._directionLights._length); shaderValues.setTexture(Scene3D.CLUSTERBUFFER, Cluster.instance._clusterTexture); } else { if (this._directionLights._length > 0) { var dirLight = this._directionLights._elements[0]; this._mainDirectionLight = dirLight; Vector3.scale(dirLight.color, dirLight._intensity, dirLight._intensityColor); dirLight.transform.worldMatrix.getForward(dirLight._direction); Vector3.normalize(dirLight._direction, dirLight._direction); shaderValues.setVector3(Scene3D.LIGHTDIRCOLOR, dirLight._intensityColor); shaderValues.setVector3(Scene3D.LIGHTDIRECTION, dirLight._direction); shaderValues.setVector3(Scene3D.SUNLIGHTDIRCOLOR, dirLight._intensityColor); shaderValues.setVector3(Scene3D.SUNLIGHTDIRECTION, dirLight._direction); shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_DIRECTIONLIGHT); } else { shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_DIRECTIONLIGHT); } if (this._pointLights._length > 0) { var poiLight = this._pointLights._elements[0]; Vector3.scale(poiLight.color, poiLight._intensity, poiLight._intensityColor); shaderValues.setVector3(Scene3D.POINTLIGHTCOLOR, poiLight._intensityColor); shaderValues.setVector3(Scene3D.POINTLIGHTPOS, poiLight.transform.position); shaderValues.setNumber(Scene3D.POINTLIGHTRANGE, poiLight.range); shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_POINTLIGHT); } else { shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_POINTLIGHT); } if (this._spotLights._length > 0) { var spotLight = this._spotLights._elements[0]; Vector3.scale(spotLight.color, spotLight._intensity, spotLight._intensityColor); shaderValues.setVector3(Scene3D.SPOTLIGHTCOLOR, spotLight._intensityColor); shaderValues.setVector3(Scene3D.SPOTLIGHTPOS, spotLight.transform.position); spotLight.transform.worldMatrix.getForward(spotLight._direction); Vector3.normalize(spotLight._direction, spotLight._direction); shaderValues.setVector3(Scene3D.SPOTLIGHTDIRECTION, spotLight._direction); shaderValues.setNumber(Scene3D.SPOTLIGHTRANGE, spotLight.range); shaderValues.setNumber(Scene3D.SPOTLIGHTSPOTANGLE, spotLight.spotAngle * Math.PI / 180); shaderValues.addDefine(Scene3DShaderDeclaration.SHADERDEFINE_SPOTLIGHT); } else { shaderValues.removeDefine(Scene3DShaderDeclaration.SHADERDEFINE_SPOTLIGHT); } } } _addScript(script) { var scripts = this._scriptPool; script._indexInPool = scripts.length; scripts.push(script); } _removeScript(script) { this._scriptPool[script._indexInPool] = null; script._indexInPool = -1; this._needClearScriptPool = true; } _preRenderScript() { var scripts = this._scriptPool; for (var i = 0, n = scripts.length; i < n; i++) { var script = scripts[i]; (script && script.enabled) && (script.onPreRender()); } } _postRenderScript() { var scripts = this._scriptPool; for (var i = 0, n = scripts.length; i < n; i++) { var script = scripts[i]; (script && script.enabled) && (script.onPostRender()); } } _addCamera(camera) { var index = this._binarySearchIndexInCameraPool(camera); var order = camera._renderingOrder; var count = this._cameraPool.length; while (index < count && this._cameraPool[index]._renderingOrder <= order) index++; this._cameraPool.splice(index, 0, camera); } _removeCamera(camera) { this._cameraPool.splice(this._cameraPool.indexOf(camera), 1); } _preCulling(context, camera, shader, replacementTag) { var cameraCullInfo = FrustumCulling._cameraCullInfo; cameraCullInfo.position = camera._transform.position; cameraCullInfo.cullingMask = camera.cullingMask; cameraCullInfo.boundFrustum = camera.boundFrustum; cameraCullInfo.useOcclusionCulling = camera.useOcclusionCulling; FrustumCulling.renderObjectCulling(cameraCullInfo, this, context, shader, replacementTag, false); } _clear(gl, state) { var viewport = state.viewport; var camera = state.camera; var renderTex = camera._getRenderTexture(); var vpX, vpY; var vpW = viewport.width; var vpH = viewport.height; if (camera._needInternalRenderTexture()) { vpX = 0; vpY = 0; } else { vpX = viewport.x; vpY = camera._getCanvasHeight() - viewport.y - vpH; } gl.viewport(vpX, vpY, vpW, vpH); var flag; var clearFlag = camera.clearFlag; if (clearFlag === exports.CameraClearFlags.Sky && !(camera.skyRenderer._isAvailable() || this._skyRenderer._isAvailable())) clearFlag = exports.CameraClearFlags.SolidColor; switch (clearFlag) { case exports.CameraClearFlags.SolidColor: var clearColor = camera.clearColor; gl.enable(gl.SCISSOR_TEST); gl.scissor(vpX, vpY, vpW, vpH); if (clearColor) gl.clearColor(clearColor.x, clearColor.y, clearColor.z, clearColor.w); else gl.clearColor(0, 0, 0, 0); if (renderTex) { flag = gl.COLOR_BUFFER_BIT; switch (renderTex.depthStencilFormat) { case Laya.RenderTextureDepthFormat.DEPTH_16: flag |= gl.DEPTH_BUFFER_BIT; break; case Laya.RenderTextureDepthFormat.STENCIL_8: flag |= gl.STENCIL_BUFFER_BIT; break; case Laya.RenderTextureDepthFormat.DEPTHSTENCIL_24_8: flag |= gl.DEPTH_BUFFER_BIT; flag |= gl.STENCIL_BUFFER_BIT; break; } } else { flag = gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT; } Laya.WebGLContext.setDepthMask(gl, true); gl.clear(flag); gl.disable(gl.SCISSOR_TEST); break; case exports.CameraClearFlags.Sky: case exports.CameraClearFlags.DepthOnly: gl.enable(gl.SCISSOR_TEST); gl.scissor(vpX, vpY, vpW, vpH); if (renderTex) { switch (renderTex.depthStencilFormat) { case Laya.RenderTextureDepthFormat.DEPTH_16: flag = gl.DEPTH_BUFFER_BIT; break; case Laya.RenderTextureDepthFormat.STENCIL_8: flag = gl.STENCIL_BUFFER_BIT; break; case Laya.RenderTextureDepthFormat.DEPTHSTENCIL_24_8: flag = gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT; break; } } else { flag = gl.DEPTH_BUFFER_BIT; } Laya.WebGLContext.setDepthMask(gl, true); gl.clear(flag); gl.disable(gl.SCISSOR_TEST); break; case exports.CameraClearFlags.Nothing: break; default: throw new Error("Scene3D:camera clearFlag invalid."); } } _renderScene(context) { var camera = context.camera; this._opaqueQueue._render(context); if (camera.clearFlag === exports.CameraClearFlags.Sky) { if (camera.skyRenderer._isAvailable()) camera.skyRenderer._render(context); else if (this._skyRenderer._isAvailable()) this._skyRenderer._render(context); } this._transparentQueue._render(context); if (FrustumCulling.debugFrustumCulling) { var renderElements = this._debugTool._render._renderElements; for (var i = 0, n = renderElements.length; i < n; i++) { renderElements[i]._update(this, context, null, null); renderElements[i]._render(context); } } } _parse(data, spriteMap) { var lightMapsData = data.lightmaps; if (lightMapsData) { var lightMapCount = lightMapsData.length; var lightmaps = new Array(lightMapCount); for (var i = 0; i < lightMapCount; i++) { var lightMap = new Lightmap(); var lightMapData = lightMapsData[i]; if (lightMapData.path) { lightMap.lightmapColor = Laya.Loader.getRes(lightMapData.path); } else { lightMap.lightmapColor = Laya.Loader.getRes(lightMapData.color.path); if (lightMapData.direction) lightMap.lightmapDirection = Laya.Loader.getRes(lightMapData.direction.path); } lightmaps[i] = lightMap; } this.lightmaps = lightmaps; } var ambientColorData = data.ambientColor; if (ambientColorData) { var ambCol = this.ambientColor; ambCol.fromArray(ambientColorData); this.ambientColor = ambCol; } var skyData = data.sky; if (skyData) { this._skyRenderer.material = Laya.Loader.getRes(skyData.material.path); switch (skyData.mesh) { case "SkyBox": this._skyRenderer.mesh = SkyBox.instance; break; case "SkyDome": this._skyRenderer.mesh = SkyDome.instance; break; default: this.skyRenderer.mesh = SkyBox.instance; } } this.enableFog = data.enableFog; this.fogStart = data.fogStart; this.fogRange = data.fogRange; var fogColorData = data.fogColor; if (fogColorData) { var fogCol = this.fogColor; fogCol.fromArray(fogColorData); this.fogColor = fogCol; } var ambientSphericalHarmonicsData = data.ambientSphericalHarmonics; if (ambientSphericalHarmonicsData) { var ambientSH = this.ambientSphericalHarmonics; for (var i = 0; i < 3; i++) { var off = i * 9; ambientSH.setCoefficients(i, ambientSphericalHarmonicsData[off], ambientSphericalHarmonicsData[off + 1], ambientSphericalHarmonicsData[off + 2], ambientSphericalHarmonicsData[off + 3], ambientSphericalHarmonicsData[off + 4], ambientSphericalHarmonicsData[off + 5], ambientSphericalHarmonicsData[off + 6], ambientSphericalHarmonicsData[off + 7], ambientSphericalHarmonicsData[off + 8]); } this.ambientSphericalHarmonics = ambientSH; } var reflectionData = data.reflection; (reflectionData != undefined) && (this.reflection = Laya.Loader.getRes(reflectionData)); var reflectionDecodingFormatData = data.reflectionDecodingFormat; (reflectionDecodingFormatData != undefined) && (this.reflectionDecodingFormat = reflectionDecodingFormatData); var ambientModeData = data.ambientMode; (ambientModeData != undefined) && (this.ambientMode = ambientModeData); var ambientSphericalHarmonicsIntensityData = data.ambientSphericalHarmonicsIntensity; (ambientSphericalHarmonicsIntensityData != undefined) && (this.ambientSphericalHarmonicsIntensity = ambientSphericalHarmonicsIntensityData); var reflectionIntensityData = data.reflectionIntensity; (reflectionIntensityData != undefined) && (this.reflectionIntensity = reflectionIntensityData); } _addRenderObject(render) { if (this._octree && render._supportOctree) { this._octree.add(render); } else { this._renders.add(render); if (Laya.Render.supportWebGLPlusCulling) { var indexInList = render._getIndexInList(); var length = this._cullingBufferIndices.length; if (indexInList >= length) { var tempIndices = this._cullingBufferIndices; var tempResult = this._cullingBufferResult; this._cullingBufferIndices = new Int32Array(length + 1024); this._cullingBufferResult = new Int32Array(length + 1024); this._cullingBufferIndices.set(tempIndices, 0); this._cullingBufferResult.set(tempResult, 0); } this._cullingBufferIndices[indexInList] = render._cullingBufferIndex; } } } _removeRenderObject(render) { if (this._octree && render._supportOctree) { this._octree.remove(render); } else { var endRender; if (Laya.Render.supportWebGLPlusCulling) { endRender = this._renders.elements[this._renders.length - 1]; } this._renders.remove(render); if (Laya.Render.supportWebGLPlusCulling) { this._cullingBufferIndices[endRender._getIndexInList()] = endRender._cullingBufferIndex; } } } _getRenderQueue(index) { if (index <= 2500) return this._opaqueQueue; else return this._transparentQueue; } _clearRenderQueue() { this._opaqueQueue.clear(); this._transparentQueue.clear(); var staticBatchManagers = StaticBatchManager._managers; for (var i = 0, n = staticBatchManagers.length; i < n; i++) staticBatchManagers[i]._clear(); var dynamicBatchManagers = DynamicBatchManager._managers; for (var i = 0, n = dynamicBatchManagers.length; i < n; i++) dynamicBatchManagers[i]._clear(); } destroy(destroyChild = true) { if (this.destroyed) return; super.destroy(destroyChild); this._skyRenderer.destroy(); this._skyRenderer = null; this._directionLights = null; this._pointLights = null; this._spotLights = null; this._alternateLights = null; this._lightmaps = null; this._shaderValues = null; this._renders = null; this._cameraPool = null; this._octree = null; this._physicsSimulation && this._physicsSimulation._destroy(); Laya.Loader.clearRes(this.url); } render(ctx, x, y) { ctx._curSubmit = Laya.SubmitBase.RENDERBASE; this._children.length > 0 && ctx.addRenderObject(this); } renderSubmit() { var gl = Laya.LayaGL.instance; this._prepareSceneToRender(); var i, n, n1; for (i = 0, n = this._cameraPool.length, n1 = n - 1; i < n; i++) { if (Laya.Render.supportWebGLPlusRendering) ShaderData.setRuntimeValueMode((i == n1) ? true : false); var camera = this._cameraPool[i]; camera.enableRender && camera.render(); } Laya.Context.set2DRenderConfig(); return 1; } getRenderType() { return 0; } releaseRender() { } reUse(context, pos) { return 0; } get customReflection() { return this._reflection; } set customReflection(value) { if (this._reflection != value) { this._shaderValues.setTexture(Scene3D.REFLECTIONTEXTURE, value || TextureCube.blackTexture); this._reflection = value; } } get reflectionMode() { return this._reflectionMode; } set reflectionMode(value) { this._reflectionMode = value; } setlightmaps(value) { var maps = this._lightmaps; for (var i = 0, n = maps.length; i < n; i++) maps[i].lightmapColor._removeReference(); if (value) { var count = value.length; maps.length = count; for (i = 0; i < count; i++) { var lightMap = value[i]; lightMap._addReference(); (maps[i]) || (maps[i] = new Lightmap()); maps[i].lightmapColor = lightMap; } } else { throw new Error("Scene3D: value value can't be null."); } } getlightmaps() { var lightmapColors = new Array(this._lightmaps.length); for (var i = 0; i < this._lightmaps.length; i++) { lightmapColors[i] = this._lightmaps[i].lightmapColor; } return lightmapColors; } } Scene3D._shadowCasterPass = new ShadowCasterPass(); Scene3D.HIERARCHY = "HIERARCHY"; Scene3D.octreeCulling = false; Scene3D.octreeInitialSize = 64.0; Scene3D.octreeInitialCenter = new Vector3(0, 0, 0); Scene3D.octreeMinNodeSize = 2.0; Scene3D.octreeLooseness = 1.25; Scene3D.REFLECTIONMODE_SKYBOX = 0; Scene3D.REFLECTIONMODE_CUSTOM = 1; Scene3D.FOGCOLOR = Shader3D.propertyNameToID("u_FogColor"); Scene3D.FOGSTART = Shader3D.propertyNameToID("u_FogStart"); Scene3D.FOGRANGE = Shader3D.propertyNameToID("u_FogRange"); Scene3D.DIRECTIONLIGHTCOUNT = Shader3D.propertyNameToID("u_DirationLightCount"); Scene3D.LIGHTBUFFER = Shader3D.propertyNameToID("u_LightBuffer"); Scene3D.CLUSTERBUFFER = Shader3D.propertyNameToID("u_LightClusterBuffer"); Scene3D.SUNLIGHTDIRECTION = Shader3D.propertyNameToID("u_SunLight.direction"); Scene3D.SUNLIGHTDIRCOLOR = Shader3D.propertyNameToID("u_SunLight.color"); Scene3D.AMBIENTSHAR = Shader3D.propertyNameToID("u_AmbientSHAr"); Scene3D.AMBIENTSHAG = Shader3D.propertyNameToID("u_AmbientSHAg"); Scene3D.AMBIENTSHAB = Shader3D.propertyNameToID("u_AmbientSHAb"); Scene3D.AMBIENTSHBR = Shader3D.propertyNameToID("u_AmbientSHBr"); Scene3D.AMBIENTSHBG = Shader3D.propertyNameToID("u_AmbientSHBg"); Scene3D.AMBIENTSHBB = Shader3D.propertyNameToID("u_AmbientSHBb"); Scene3D.AMBIENTSHC = Shader3D.propertyNameToID("u_AmbientSHC"); Scene3D.REFLECTIONPROBE = Shader3D.propertyNameToID("u_ReflectionProbe"); Scene3D.REFLECTIONCUBE_HDR_PARAMS = Shader3D.propertyNameToID("u_ReflectCubeHDRParams"); Scene3D.LIGHTDIRECTION = Shader3D.propertyNameToID("u_DirectionLight.direction"); Scene3D.LIGHTDIRCOLOR = Shader3D.propertyNameToID("u_DirectionLight.color"); Scene3D.POINTLIGHTPOS = Shader3D.propertyNameToID("u_PointLight.position"); Scene3D.POINTLIGHTRANGE = Shader3D.propertyNameToID("u_PointLight.range"); Scene3D.POINTLIGHTATTENUATION = Shader3D.propertyNameToID("u_PointLight.attenuation"); Scene3D.POINTLIGHTCOLOR = Shader3D.propertyNameToID("u_PointLight.color"); Scene3D.SPOTLIGHTPOS = Shader3D.propertyNameToID("u_SpotLight.position"); Scene3D.SPOTLIGHTDIRECTION = Shader3D.propertyNameToID("u_SpotLight.direction"); Scene3D.SPOTLIGHTSPOTANGLE = Shader3D.propertyNameToID("u_SpotLight.spot"); Scene3D.SPOTLIGHTRANGE = Shader3D.propertyNameToID("u_SpotLight.range"); Scene3D.SPOTLIGHTCOLOR = Shader3D.propertyNameToID("u_SpotLight.color"); Scene3D.AMBIENTCOLOR = Shader3D.propertyNameToID("u_AmbientColor"); Scene3D.REFLECTIONTEXTURE = Shader3D.propertyNameToID("u_ReflectTexture"); Scene3D.TIME = Shader3D.propertyNameToID("u_Time"); Scene3D._configDefineValues = new DefineDatas(); class ShaderPass extends Laya.ShaderCompile { constructor(owner, vs, ps, stateMap) { super(vs, ps, null); this._cacheSharders = {}; this._cacheShaderHierarchy = 1; this._renderState = new RenderState(); this._validDefine = new DefineDatas(); this._tags = {}; this._owner = owner; this._stateMap = stateMap; for (var k in this.defs) this._validDefine.add(Shader3D.getDefineByName(k)); } get renderState() { return this._renderState; } _compileToTree(parent, lines, start, includefiles, defs) { var node, preNode; var text, name, fname; var ofs, words, noUseNode; var i, n, j; for (i = start; i < lines.length; i++) { text = lines[i]; if (text.length < 1) continue; ofs = text.indexOf("//"); if (ofs === 0) continue; if (ofs >= 0) text = text.substr(0, ofs); node = noUseNode || new Laya.ShaderNode(includefiles); noUseNode = null; node.text = text; if ((ofs = text.indexOf("#")) >= 0) { name = "#"; for (j = ofs + 1, n = text.length; j < n; j++) { var c = text.charAt(j); if (c === ' ' || c === '\t' || c === '?') break; name += c; } node.name = name; switch (name) { case "#ifdef": case "#ifndef": node.setParent(parent); parent = node; if (defs) { words = text.substr(j).split(Laya.ShaderCompile._splitToWordExps3); for (j = 0; j < words.length; j++) { text = words[j]; text.length && (defs[text] = true); } } continue; case "#if": case "#elif": node.setParent(parent); parent = node; if (defs) { words = text.substr(j).split(Laya.ShaderCompile._splitToWordExps3); for (j = 0; j < words.length; j++) { text = words[j]; text.length && text != "defined" && (defs[text] = true); } } continue; case "#else": parent = parent.parent; preNode = parent.childs[parent.childs.length - 1]; node.setParent(parent); parent = node; continue; case "#endif": parent = parent.parent; preNode = parent.childs[parent.childs.length - 1]; node.setParent(parent); continue; case "#include": words = Laya.ShaderCompile.splitToWords(text, null); var inlcudeFile = Laya.ShaderCompile.includes[words[1]]; if (!inlcudeFile) { throw "ShaderCompile error no this include file:" + words[1]; } if ((ofs = words[0].indexOf("?")) < 0) { node.setParent(parent); text = inlcudeFile.getWith(words[2] == 'with' ? words[3] : null); this._compileToTree(node, text.split('\n'), 0, includefiles, defs); node.text = ""; continue; } node.setCondition(words[0].substr(ofs + 1), Laya.ShaderCompile.IFDEF_YES); node.text = inlcudeFile.getWith(words[2] == 'with' ? words[3] : null); break; case "#import": words = Laya.ShaderCompile.splitToWords(text, null); fname = words[1]; includefiles.push({ node: node, file: Laya.ShaderCompile.includes[fname], ofs: node.text.length }); continue; } } else { preNode = parent.childs[parent.childs.length - 1]; if (preNode && !preNode.name) { includefiles.length > 0 && Laya.ShaderCompile.splitToWords(text, preNode); noUseNode = node; preNode.text += "\n" + text; continue; } includefiles.length > 0 && Laya.ShaderCompile.splitToWords(text, node); } node.setParent(parent); } } _resizeCacheShaderMap(cacheMap, hierarchy, resizeLength) { var end = this._cacheShaderHierarchy - 1; if (hierarchy == end) { for (var k in cacheMap) { var shader = cacheMap[k]; for (var i = 0, n = resizeLength - end; i < n; i++) { if (i == n - 1) cacheMap[0] = shader; else cacheMap = cacheMap[i == 0 ? k : 0] = {}; } } this._cacheShaderHierarchy = resizeLength; } else { for (var k in cacheMap) this._resizeCacheShaderMap(cacheMap[k], ++hierarchy, resizeLength); } } _addDebugShaderVariantCollection(compileDefine, outDebugDefines, outDebugDefineMask) { var dbugShaderVariantInfo = Shader3D._debugShaderVariantInfo; var debugSubShader = this._owner; var debugShader = debugSubShader._owner; var mask = compileDefine._mask; Shader3D._getNamesByDefineData(compileDefine, outDebugDefines); outDebugDefineMask.length = mask.length; for (var i = 0, n = mask.length; i < n; i++) outDebugDefineMask[i] = mask[i]; if (dbugShaderVariantInfo) dbugShaderVariantInfo.setValue(debugShader, debugShader._subShaders.indexOf(debugSubShader), debugSubShader._passes.indexOf(this), outDebugDefines); else Shader3D._debugShaderVariantInfo = dbugShaderVariantInfo = new ShaderVariant(debugShader, debugShader._subShaders.indexOf(debugSubShader), debugSubShader._passes.indexOf(this), outDebugDefines); Shader3D.debugShaderVariantCollection.add(dbugShaderVariantInfo); } withCompile(compileDefine) { var debugDefineString = ShaderPass._debugDefineString; var debugDefineMask = ShaderPass._debugDefineMask; var debugMaskLength; compileDefine._intersectionDefineDatas(this._validDefine); if (Shader3D.debugMode) { debugMaskLength = compileDefine._length; this._addDebugShaderVariantCollection(compileDefine, debugDefineString, debugDefineMask); } compileDefine.addDefineDatas(Scene3D._configDefineValues); var cacheShaders = this._cacheSharders; var maskLength = compileDefine._length; if (maskLength > this._cacheShaderHierarchy) { this._resizeCacheShaderMap(cacheShaders, 0, maskLength); this._cacheShaderHierarchy = maskLength; } var mask = compileDefine._mask; var endIndex = compileDefine._length - 1; var maxEndIndex = this._cacheShaderHierarchy - 1; for (var i = 0; i < maxEndIndex; i++) { var subMask = endIndex < i ? 0 : mask[i]; var subCacheShaders = cacheShaders[subMask]; (subCacheShaders) || (cacheShaders[subMask] = subCacheShaders = {}); cacheShaders = subCacheShaders; } var cacheKey = endIndex < maxEndIndex ? 0 : mask[maxEndIndex]; var shader = cacheShaders[cacheKey]; if (shader) return shader; var defineString = ShaderPass._defineString; Shader3D._getNamesByDefineData(compileDefine, defineString); var config = Config3D._config; var clusterSlices = config.lightClusterCount; var defMap = {}; var vertexHead; var fragmentHead; var defineStr = ""; if (Laya.WebGL._isWebGL2) { vertexHead = `#version 300 es\n #define attribute in #define varying out #define texture2D texture\n`; fragmentHead = `#version 300 es\n #define varying in out highp vec4 pc_fragColor; #define gl_FragColor pc_fragColor #define gl_FragDepthEXT gl_FragDepth #define texture2D texture #define textureCube texture #define texture2DProj textureProj #define texture2DLodEXT textureLod #define texture2DProjLodEXT textureProjLod #define textureCubeLodEXT textureLod #define texture2DGradEXT textureGrad #define texture2DProjGradEXT textureProjGrad #define textureCubeGradEXT textureGrad\n`; } else { vertexHead = ""; fragmentHead = `#ifdef GL_EXT_shader_texture_lod #extension GL_EXT_shader_texture_lod : enable #endif #if !defined(GL_EXT_shader_texture_lod) #define texture1DLodEXT texture1D #define texture2DLodEXT texture2D #define texture2DProjLodEXT texture2DProj #define texture3DLodEXT texture3D #define textureCubeLodEXT textureCube #endif\n`; } defineStr += "#define MAX_LIGHT_COUNT " + config.maxLightCount + "\n"; defineStr += "#define MAX_LIGHT_COUNT_PER_CLUSTER " + config._maxAreaLightCountPerClusterAverage + "\n"; defineStr += "#define CLUSTER_X_COUNT " + clusterSlices.x + "\n"; defineStr += "#define CLUSTER_Y_COUNT " + clusterSlices.y + "\n"; defineStr += "#define CLUSTER_Z_COUNT " + clusterSlices.z + "\n"; defineStr += "#define SHADER_CAPAILITY_LEVEL " + Laya.SystemUtils._shaderCapailityLevel + "\n"; for (var i = 0, n = defineString.length; i < n; i++) { var def = defineString[i]; defineStr += "#define " + def + "\n"; defMap[def] = true; } var vs = this._VS.toscript(defMap, []); var vsVersion = ''; if (vs[0].indexOf('#version') == 0) { vsVersion = vs[0] + '\n'; vs.shift(); } var ps = this._PS.toscript(defMap, []); var psVersion = ''; if (ps[0].indexOf('#version') == 0) { psVersion = ps[0] + '\n'; ps.shift(); } shader = new ShaderInstance(vsVersion + vertexHead + defineStr + vs.join('\n'), psVersion + fragmentHead + defineStr + ps.join('\n'), this._owner._attributeMap || this._owner._owner._attributeMap, this._owner._uniformMap || this._owner._owner._uniformMap, this); cacheShaders[cacheKey] = shader; if (Shader3D.debugMode) { var defStr = ""; var defMask = ""; for (var i = 0, n = debugMaskLength; i < n; i++) (i == n - 1) ? defMask += debugDefineMask[i] : defMask += debugDefineMask[i] + ","; for (var i = 0, n = debugDefineString.length; i < n; i++) (i == n - 1) ? defStr += debugDefineString[i] : defStr += debugDefineString[i] + ","; console.log("%cLayaAir: Shader Compile Information---ShaderName:" + this._owner._owner._name + " SubShaderIndex:" + this._owner._owner._subShaders.indexOf(this._owner) + " PassIndex:" + this._owner._passes.indexOf(this) + " DefineMask:[" + defMask + "]" + " DefineNames:[" + defStr + "]", "color:green"); } return shader; } setTag(key, value) { if (value) this._tags[key] = value; else delete this._tags[key]; } getTag(key) { return this._tags[key]; } } ShaderPass._defineString = []; ShaderPass._debugDefineString = []; ShaderPass._debugDefineMask = []; class SubShader { constructor(attributeMap, uniformMap) { this._flags = {}; this._passes = []; this._attributeMap = attributeMap; this._uniformMap = uniformMap; } setFlag(key, value) { if (value) this._flags[key] = value; else delete this._flags[key]; } getFlag(key) { return this._flags[key]; } addShaderPass(vs, ps, stateMap = null, pipelineMode = "Forward") { var shaderPass = new ShaderPass(this, vs, ps, stateMap); shaderPass._pipelineMode = pipelineMode; this._passes.push(shaderPass); return shaderPass; } } (function (PBRSpecularSmoothnessSource) { PBRSpecularSmoothnessSource[PBRSpecularSmoothnessSource["SpecularTextureAlpha"] = 0] = "SpecularTextureAlpha"; PBRSpecularSmoothnessSource[PBRSpecularSmoothnessSource["AlbedoTextureAlpha"] = 1] = "AlbedoTextureAlpha"; })(exports.PBRSpecularSmoothnessSource || (exports.PBRSpecularSmoothnessSource = {})); class PBRSpecularMaterial extends PBRMaterial { constructor() { super(); this.setShaderName("PBRSpecular"); this._shaderValues.setVector(PBRSpecularMaterial.SPECULARCOLOR, new Vector4(0.2, 0.2, 0.2, 1.0)); } static __init__() { PBRSpecularMaterial.SHADERDEFINE_SPECULARGLOSSTEXTURE = Shader3D.getDefineByName("SPECULARGLOSSTEXTURE"); PBRSpecularMaterial.SHADERDEFINE_SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA = Shader3D.getDefineByName("SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA"); var attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0, 'a_Normal': VertexMesh.MESH_NORMAL0, 'a_Tangent0': VertexMesh.MESH_TANGENT0, 'a_Texcoord0': VertexMesh.MESH_TEXTURECOORDINATE0, 'a_Texcoord1': VertexMesh.MESH_TEXTURECOORDINATE1, 'a_BoneWeights': VertexMesh.MESH_BLENDWEIGHT0, 'a_BoneIndices': VertexMesh.MESH_BLENDINDICES0, 'a_MvpMatrix': VertexMesh.MESH_MVPMATRIX_ROW0, 'a_WorldMat': VertexMesh.MESH_WORLDMATRIX_ROW0 }; var uniformMap = { 'u_Bones': Shader3D.PERIOD_CUSTOM, 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_WorldMat': Shader3D.PERIOD_SPRITE, 'u_LightmapScaleOffset': Shader3D.PERIOD_SPRITE, 'u_LightMap': Shader3D.PERIOD_SPRITE, 'u_LightMapDirection': Shader3D.PERIOD_SPRITE, 'u_SimpleAnimatorTexture': Shader3D.PERIOD_SPRITE, 'u_SimpleAnimatorParams': Shader3D.PERIOD_SPRITE, 'u_SimpleAnimatorTextureSize': Shader3D.PERIOD_SPRITE, 'u_CameraPos': Shader3D.PERIOD_CAMERA, 'u_View': Shader3D.PERIOD_CAMERA, 'u_ProjectionParams': Shader3D.PERIOD_CAMERA, 'u_Viewport': Shader3D.PERIOD_CAMERA, 'u_ViewProjection': Shader3D.PERIOD_CAMERA, 'u_AlphaTestValue': Shader3D.PERIOD_MATERIAL, 'u_AlbedoColor': Shader3D.PERIOD_MATERIAL, 'u_EmissionColor': Shader3D.PERIOD_MATERIAL, 'u_AlbedoTexture': Shader3D.PERIOD_MATERIAL, 'u_NormalTexture': Shader3D.PERIOD_MATERIAL, 'u_ParallaxTexture': Shader3D.PERIOD_MATERIAL, 'u_OcclusionTexture': Shader3D.PERIOD_MATERIAL, 'u_EmissionTexture': Shader3D.PERIOD_MATERIAL, 'u_Smoothness': Shader3D.PERIOD_MATERIAL, 'u_SmoothnessScale': Shader3D.PERIOD_MATERIAL, 'u_occlusionStrength': Shader3D.PERIOD_MATERIAL, 'u_NormalScale': Shader3D.PERIOD_MATERIAL, 'u_ParallaxScale': Shader3D.PERIOD_MATERIAL, 'u_TilingOffset': Shader3D.PERIOD_MATERIAL, 'u_SpecGlossTexture': Shader3D.PERIOD_MATERIAL, 'u_SpecularColor': Shader3D.PERIOD_MATERIAL, 'u_ReflectTexture': Shader3D.PERIOD_SCENE, 'u_ReflectIntensity': Shader3D.PERIOD_SCENE, 'u_AmbientColor': Shader3D.PERIOD_SCENE, 'u_FogStart': Shader3D.PERIOD_SCENE, 'u_FogRange': Shader3D.PERIOD_SCENE, 'u_FogColor': Shader3D.PERIOD_SCENE, 'u_DirationLightCount': Shader3D.PERIOD_SCENE, 'u_LightBuffer': Shader3D.PERIOD_SCENE, 'u_LightClusterBuffer': Shader3D.PERIOD_SCENE, 'u_ShadowBias': Shader3D.PERIOD_SCENE, 'u_ShadowLightDirection': Shader3D.PERIOD_SCENE, 'u_ShadowMap': Shader3D.PERIOD_SCENE, 'u_ShadowParams': Shader3D.PERIOD_SCENE, 'u_ShadowSplitSpheres': Shader3D.PERIOD_SCENE, 'u_ShadowMatrices': Shader3D.PERIOD_SCENE, 'u_ShadowMapSize': Shader3D.PERIOD_SCENE, 'u_SpotShadowMap': Shader3D.PERIOD_SCENE, 'u_SpotViewProjectMatrix': Shader3D.PERIOD_SCENE, 'u_ShadowLightPosition': Shader3D.PERIOD_SCENE, 'u_AmbientSHAr': Shader3D.PERIOD_SCENE, 'u_AmbientSHAg': Shader3D.PERIOD_SCENE, 'u_AmbientSHAb': Shader3D.PERIOD_SCENE, 'u_AmbientSHBr': Shader3D.PERIOD_SCENE, 'u_AmbientSHBg': Shader3D.PERIOD_SCENE, 'u_AmbientSHBb': Shader3D.PERIOD_SCENE, 'u_AmbientSHC': Shader3D.PERIOD_SCENE, 'u_ReflectionProbe': Shader3D.PERIOD_SCENE, 'u_ReflectCubeHDRParams': Shader3D.PERIOD_SCENE, 'u_DirectionLight.direction': Shader3D.PERIOD_SCENE, 'u_DirectionLight.color': Shader3D.PERIOD_SCENE, 'u_PointLight.position': Shader3D.PERIOD_SCENE, 'u_PointLight.range': Shader3D.PERIOD_SCENE, 'u_PointLight.color': Shader3D.PERIOD_SCENE, 'u_SpotLight.position': Shader3D.PERIOD_SCENE, 'u_SpotLight.direction': Shader3D.PERIOD_SCENE, 'u_SpotLight.range': Shader3D.PERIOD_SCENE, 'u_SpotLight.spot': Shader3D.PERIOD_SCENE, 'u_SpotLight.color': Shader3D.PERIOD_SCENE }; var stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; var shader = Shader3D.add("PBRSpecular", attributeMap, uniformMap, true); var subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(PBRVS, PBRPS, stateMap, "Forward"); subShader.addShaderPass(PBRShadowCasterVS, PBRShadowCasterPS, stateMap, "ShadowCaster"); } get specularTexture() { return this._shaderValues.getTexture(PBRSpecularMaterial.SPECULARTEXTURE); } set specularTexture(value) { if (value) this._shaderValues.addDefine(PBRSpecularMaterial.SHADERDEFINE_SPECULARGLOSSTEXTURE); else this._shaderValues.removeDefine(PBRSpecularMaterial.SHADERDEFINE_SPECULARGLOSSTEXTURE); this._shaderValues.setTexture(PBRSpecularMaterial.SPECULARTEXTURE, value); } get specularColor() { return this._shaderValues.getVector(PBRSpecularMaterial.SPECULARCOLOR); } set specularColor(value) { this._shaderValues.setVector(PBRSpecularMaterial.SPECULARCOLOR, value); } clone() { var dest = new PBRSpecularMaterial(); this.cloneTo(dest); return dest; } } PBRSpecularMaterial.SPECULARTEXTURE = Shader3D.propertyNameToID("u_SpecGlossTexture"); PBRSpecularMaterial.SPECULARCOLOR = Shader3D.propertyNameToID("u_SpecularColor"); var PBRPS$1 = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n\tprecision highp int;\r\n#else\r\n\tprecision mediump float;\r\n\tprecision mediump int;\r\n#endif\r\n\r\n#include \"Lighting.glsl\";\r\n#include \"Shadow.glsl\"\r\n#include \"PBRFSInput.glsl\";\r\n#include \"LayaPBRBRDF.glsl\";\r\n#include \"GlobalIllumination.glsl\";\r\n#include \"PBRCore.glsl\";\r\n\r\nvoid main()\r\n{\r\n\tfragmentForward();\r\n}"; var PBRVS$1 = "#include \"Lighting.glsl\";\r\n#include \"Shadow.glsl\"\r\n#include \"PBRVSInput.glsl\";\r\n#include \"PBRVertex.glsl\";\r\n\r\nvoid main()\r\n{\r\n\tvertexForward();\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}"; var PBRShadowCasterPS$1 = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n\tprecision highp int;\r\n#else\r\n\tprecision mediump float;\r\n\tprecision mediump int;\r\n#endif\r\n\r\n#include \"ShadowCasterFS.glsl\"\r\n\r\nvoid main()\r\n{\r\n\tgl_FragColor=shadowCasterFragment();\r\n}"; var PBRShadowCasterVS$1 = "#include \"ShadowCasterVS.glsl\"\r\n\r\nvoid main()\r\n{\r\n\tvec4 positionCS = shadowCasterVertex();\r\n\tgl_Position=remapGLPositionZ(positionCS);\r\n}"; (function (PBRMetallicSmoothnessSource) { PBRMetallicSmoothnessSource[PBRMetallicSmoothnessSource["MetallicGlossTextureAlpha"] = 0] = "MetallicGlossTextureAlpha"; PBRMetallicSmoothnessSource[PBRMetallicSmoothnessSource["AlbedoTextureAlpha"] = 1] = "AlbedoTextureAlpha"; })(exports.PBRMetallicSmoothnessSource || (exports.PBRMetallicSmoothnessSource = {})); class PBRStandardMaterial extends PBRMaterial { constructor() { super(); this._smoothnessSource = 0; this.setShaderName("PBR"); this._shaderValues.setNumber(PBRStandardMaterial.METALLIC, 0.0); } static __init__() { PBRStandardMaterial.SHADERDEFINE_METALLICGLOSSTEXTURE = Shader3D.getDefineByName("METALLICGLOSSTEXTURE"); PBRStandardMaterial.SHADERDEFINE_SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA = Shader3D.getDefineByName("SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA"); var attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0, 'a_Normal': VertexMesh.MESH_NORMAL0, 'a_Tangent0': VertexMesh.MESH_TANGENT0, 'a_Texcoord0': VertexMesh.MESH_TEXTURECOORDINATE0, 'a_Texcoord1': VertexMesh.MESH_TEXTURECOORDINATE1, 'a_BoneWeights': VertexMesh.MESH_BLENDWEIGHT0, 'a_BoneIndices': VertexMesh.MESH_BLENDINDICES0, 'a_MvpMatrix': VertexMesh.MESH_MVPMATRIX_ROW0, 'a_WorldMat': VertexMesh.MESH_WORLDMATRIX_ROW0 }; var uniformMap = { 'u_Bones': Shader3D.PERIOD_CUSTOM, 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_WorldMat': Shader3D.PERIOD_SPRITE, 'u_LightmapScaleOffset': Shader3D.PERIOD_SPRITE, 'u_LightMap': Shader3D.PERIOD_SPRITE, 'u_LightMapDirection': Shader3D.PERIOD_SPRITE, 'u_SimpleAnimatorTexture': Shader3D.PERIOD_SPRITE, 'u_SimpleAnimatorParams': Shader3D.PERIOD_SPRITE, 'u_SimpleAnimatorTextureSize': Shader3D.PERIOD_SPRITE, 'u_CameraPos': Shader3D.PERIOD_CAMERA, 'u_View': Shader3D.PERIOD_CAMERA, 'u_ProjectionParams': Shader3D.PERIOD_CAMERA, 'u_Viewport': Shader3D.PERIOD_CAMERA, 'u_ViewProjection': Shader3D.PERIOD_CAMERA, 'u_AlphaTestValue': Shader3D.PERIOD_MATERIAL, 'u_AlbedoColor': Shader3D.PERIOD_MATERIAL, 'u_EmissionColor': Shader3D.PERIOD_MATERIAL, 'u_AlbedoTexture': Shader3D.PERIOD_MATERIAL, 'u_NormalTexture': Shader3D.PERIOD_MATERIAL, 'u_ParallaxTexture': Shader3D.PERIOD_MATERIAL, 'u_OcclusionTexture': Shader3D.PERIOD_MATERIAL, 'u_EmissionTexture': Shader3D.PERIOD_MATERIAL, 'u_Smoothness': Shader3D.PERIOD_MATERIAL, 'u_SmoothnessScale': Shader3D.PERIOD_MATERIAL, 'u_occlusionStrength': Shader3D.PERIOD_MATERIAL, 'u_NormalScale': Shader3D.PERIOD_MATERIAL, 'u_ParallaxScale': Shader3D.PERIOD_MATERIAL, 'u_TilingOffset': Shader3D.PERIOD_MATERIAL, 'u_MetallicGlossTexture': Shader3D.PERIOD_MATERIAL, 'u_Metallic': Shader3D.PERIOD_MATERIAL, 'u_ReflectTexture': Shader3D.PERIOD_SCENE, 'u_ReflectIntensity': Shader3D.PERIOD_SCENE, 'u_AmbientColor': Shader3D.PERIOD_SCENE, 'u_FogStart': Shader3D.PERIOD_SCENE, 'u_FogRange': Shader3D.PERIOD_SCENE, 'u_FogColor': Shader3D.PERIOD_SCENE, 'u_DirationLightCount': Shader3D.PERIOD_SCENE, 'u_LightBuffer': Shader3D.PERIOD_SCENE, 'u_LightClusterBuffer': Shader3D.PERIOD_SCENE, 'u_ShadowBias': Shader3D.PERIOD_SCENE, 'u_ShadowLightDirection': Shader3D.PERIOD_SCENE, 'u_ShadowMap': Shader3D.PERIOD_SCENE, 'u_ShadowParams': Shader3D.PERIOD_SCENE, 'u_ShadowSplitSpheres': Shader3D.PERIOD_SCENE, 'u_ShadowMatrices': Shader3D.PERIOD_SCENE, 'u_ShadowMapSize': Shader3D.PERIOD_SCENE, 'u_SpotShadowMap': Shader3D.PERIOD_SCENE, 'u_SpotViewProjectMatrix': Shader3D.PERIOD_SCENE, 'u_ShadowLightPosition': Shader3D.PERIOD_SCENE, 'u_AmbientSHAr': Shader3D.PERIOD_SCENE, 'u_AmbientSHAg': Shader3D.PERIOD_SCENE, 'u_AmbientSHAb': Shader3D.PERIOD_SCENE, 'u_AmbientSHBr': Shader3D.PERIOD_SCENE, 'u_AmbientSHBg': Shader3D.PERIOD_SCENE, 'u_AmbientSHBb': Shader3D.PERIOD_SCENE, 'u_AmbientSHC': Shader3D.PERIOD_SCENE, 'u_ReflectionProbe': Shader3D.PERIOD_SCENE, 'u_ReflectCubeHDRParams': Shader3D.PERIOD_SCENE, 'u_DirectionLight.direction': Shader3D.PERIOD_SCENE, 'u_DirectionLight.color': Shader3D.PERIOD_SCENE, 'u_PointLight.position': Shader3D.PERIOD_SCENE, 'u_PointLight.range': Shader3D.PERIOD_SCENE, 'u_PointLight.color': Shader3D.PERIOD_SCENE, 'u_SpotLight.position': Shader3D.PERIOD_SCENE, 'u_SpotLight.direction': Shader3D.PERIOD_SCENE, 'u_SpotLight.range': Shader3D.PERIOD_SCENE, 'u_SpotLight.spot': Shader3D.PERIOD_SCENE, 'u_SpotLight.color': Shader3D.PERIOD_SCENE }; var stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; var shader = Shader3D.add("PBR", attributeMap, uniformMap, true); var subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(PBRVS$1, PBRPS$1, stateMap, "Forward"); subShader.addShaderPass(PBRShadowCasterVS$1, PBRShadowCasterPS$1, stateMap, "ShadowCaster"); } get metallicGlossTexture() { return this._shaderValues.getTexture(PBRStandardMaterial.METALLICGLOSSTEXTURE); } set metallicGlossTexture(value) { if (value) this._shaderValues.addDefine(PBRStandardMaterial.SHADERDEFINE_METALLICGLOSSTEXTURE); else this._shaderValues.removeDefine(PBRStandardMaterial.SHADERDEFINE_METALLICGLOSSTEXTURE); this._shaderValues.setTexture(PBRStandardMaterial.METALLICGLOSSTEXTURE, value); } get metallic() { return this._shaderValues.getNumber(PBRStandardMaterial.METALLIC); } set metallic(value) { this._shaderValues.setNumber(PBRStandardMaterial.METALLIC, Math.max(0.0, Math.min(1.0, value))); } get smoothnessSource() { return this._smoothnessSource; } set smoothnessSource(value) { if (value) this._shaderValues.addDefine(PBRStandardMaterial.SHADERDEFINE_SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA); else this._shaderValues.removeDefine(PBRStandardMaterial.SHADERDEFINE_SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA); this._smoothnessSource = value; } clone() { var dest = new PBRStandardMaterial(); this.cloneTo(dest); return dest; } } PBRStandardMaterial.METALLICGLOSSTEXTURE = Shader3D.propertyNameToID("u_MetallicGlossTexture"); PBRStandardMaterial.METALLIC = Shader3D.propertyNameToID("u_Metallic"); class SkyBoxMaterial extends Material { constructor() { super(); this.setShaderName("SkyBox"); this.tintColor = new Vector4(0.5, 0.5, 0.5, 0.5); this.exposure = 1.0; this.rotation = 0; } static __initDefine__() { } get tintColor() { return this._shaderValues.getVector(SkyBoxMaterial.TINTCOLOR); } set tintColor(value) { this._shaderValues.setVector(SkyBoxMaterial.TINTCOLOR, value); } get exposure() { return this._shaderValues.getNumber(SkyBoxMaterial.EXPOSURE); } set exposure(value) { this._shaderValues.setNumber(SkyBoxMaterial.EXPOSURE, value); } get rotation() { return this._shaderValues.getNumber(SkyBoxMaterial.ROTATION); } set rotation(value) { this._shaderValues.setNumber(SkyBoxMaterial.ROTATION, value); } get textureCube() { return this._shaderValues.getTexture(SkyBoxMaterial.TEXTURECUBE); } set textureCube(value) { this._shaderValues.setTexture(SkyBoxMaterial.TEXTURECUBE, value); } clone() { var dest = new SkyBoxMaterial(); this.cloneTo(dest); return dest; } } SkyBoxMaterial.TINTCOLOR = Shader3D.propertyNameToID("u_TintColor"); SkyBoxMaterial.EXPOSURE = Shader3D.propertyNameToID("u_Exposure"); SkyBoxMaterial.ROTATION = Shader3D.propertyNameToID("u_Rotation"); SkyBoxMaterial.TEXTURECUBE = Shader3D.propertyNameToID("u_CubeTexture"); class SkyProceduralMaterial extends Material { constructor() { super(); this.setShaderName("SkyBoxProcedural"); this.sunDisk = SkyProceduralMaterial.SUN_HIGH_QUALITY; this.sunSize = 0.04; this.sunSizeConvergence = 5; this.atmosphereThickness = 1.0; this.skyTint = new Vector4(0.5, 0.5, 0.5, 1.0); this.groundTint = new Vector4(0.369, 0.349, 0.341, 1.0); this.exposure = 1.3; } static __initDefine__() { SkyProceduralMaterial.SHADERDEFINE_SUN_HIGH_QUALITY = Shader3D.getDefineByName("SUN_HIGH_QUALITY"); SkyProceduralMaterial.SHADERDEFINE_SUN_SIMPLE = Shader3D.getDefineByName("SUN_SIMPLE"); } get sunDisk() { return this._sunDisk; } set sunDisk(value) { switch (value) { case SkyProceduralMaterial.SUN_HIGH_QUALITY: this._shaderValues.removeDefine(SkyProceduralMaterial.SHADERDEFINE_SUN_SIMPLE); this._shaderValues.addDefine(SkyProceduralMaterial.SHADERDEFINE_SUN_HIGH_QUALITY); break; case SkyProceduralMaterial.SUN_SIMPLE: this._shaderValues.removeDefine(SkyProceduralMaterial.SHADERDEFINE_SUN_HIGH_QUALITY); this._shaderValues.addDefine(SkyProceduralMaterial.SHADERDEFINE_SUN_SIMPLE); break; case SkyProceduralMaterial.SUN_NODE: this._shaderValues.removeDefine(SkyProceduralMaterial.SHADERDEFINE_SUN_HIGH_QUALITY); this._shaderValues.removeDefine(SkyProceduralMaterial.SHADERDEFINE_SUN_SIMPLE); break; default: throw "SkyBoxProceduralMaterial: unknown sun value."; } this._sunDisk = value; } get sunSize() { return this._shaderValues.getNumber(SkyProceduralMaterial.SUNSIZE); } set sunSize(value) { value = Math.min(Math.max(0.0, value), 1.0); this._shaderValues.setNumber(SkyProceduralMaterial.SUNSIZE, value); } get sunSizeConvergence() { return this._shaderValues.getNumber(SkyProceduralMaterial.SUNSIZECONVERGENCE); } set sunSizeConvergence(value) { value = Math.min(Math.max(0.0, value), 20.0); this._shaderValues.setNumber(SkyProceduralMaterial.SUNSIZECONVERGENCE, value); } get atmosphereThickness() { return this._shaderValues.getNumber(SkyProceduralMaterial.ATMOSPHERETHICKNESS); } set atmosphereThickness(value) { value = Math.min(Math.max(0.0, value), 5.0); this._shaderValues.setNumber(SkyProceduralMaterial.ATMOSPHERETHICKNESS, value); } get skyTint() { return this._shaderValues.getVector(SkyProceduralMaterial.SKYTINT); } set skyTint(value) { this._shaderValues.setVector(SkyProceduralMaterial.SKYTINT, value); } get groundTint() { return this._shaderValues.getVector(SkyProceduralMaterial.GROUNDTINT); } set groundTint(value) { this._shaderValues.setVector(SkyProceduralMaterial.GROUNDTINT, value); } get exposure() { return this._shaderValues.getNumber(SkyProceduralMaterial.EXPOSURE); } set exposure(value) { value = Math.min(Math.max(0.0, value), 8.0); this._shaderValues.setNumber(SkyProceduralMaterial.EXPOSURE, value); } clone() { var dest = new SkyProceduralMaterial(); this.cloneTo(dest); return dest; } } SkyProceduralMaterial.SUN_NODE = 0; SkyProceduralMaterial.SUN_SIMPLE = 1; SkyProceduralMaterial.SUN_HIGH_QUALITY = 2; SkyProceduralMaterial.SUNSIZE = Shader3D.propertyNameToID("u_SunSize"); SkyProceduralMaterial.SUNSIZECONVERGENCE = Shader3D.propertyNameToID("u_SunSizeConvergence"); SkyProceduralMaterial.ATMOSPHERETHICKNESS = Shader3D.propertyNameToID("u_AtmosphereThickness"); SkyProceduralMaterial.SKYTINT = Shader3D.propertyNameToID("u_SkyTint"); SkyProceduralMaterial.GROUNDTINT = Shader3D.propertyNameToID("u_GroundTint"); SkyProceduralMaterial.EXPOSURE = Shader3D.propertyNameToID("u_Exposure"); class UnlitMaterial extends Material { constructor() { super(); this._albedoColor = new Vector4(1.0, 1.0, 1.0, 1.0); this._albedoIntensity = 1.0; this._enableVertexColor = false; this.setShaderName("Unlit"); this._shaderValues.setVector(UnlitMaterial.ALBEDOCOLOR, new Vector4(1.0, 1.0, 1.0, 1.0)); this.renderMode = UnlitMaterial.RENDERMODE_OPAQUE; } static __initDefine__() { UnlitMaterial.SHADERDEFINE_ALBEDOTEXTURE = Shader3D.getDefineByName("ALBEDOTEXTURE"); UnlitMaterial.SHADERDEFINE_TILINGOFFSET = Shader3D.getDefineByName("TILINGOFFSET"); UnlitMaterial.SHADERDEFINE_ENABLEVERTEXCOLOR = Shader3D.getDefineByName("ENABLEVERTEXCOLOR"); } get _ColorR() { return this._albedoColor.x; } set _ColorR(value) { this._albedoColor.x = value; this.albedoColor = this._albedoColor; } get _ColorG() { return this._albedoColor.y; } set _ColorG(value) { this._albedoColor.y = value; this.albedoColor = this._albedoColor; } get _ColorB() { return this._albedoColor.z; } set _ColorB(value) { this._albedoColor.z = value; this.albedoColor = this._albedoColor; } get _ColorA() { return this._albedoColor.w; } set _ColorA(value) { this._albedoColor.w = value; this.albedoColor = this._albedoColor; } get _AlbedoIntensity() { return this._albedoIntensity; } set _AlbedoIntensity(value) { if (this._albedoIntensity !== value) { var finalAlbedo = this._shaderValues.getVector(UnlitMaterial.ALBEDOCOLOR); Vector4.scale(this._albedoColor, value, finalAlbedo); this._albedoIntensity = value; this._shaderValues.setVector(UnlitMaterial.ALBEDOCOLOR, finalAlbedo); } } get _MainTex_STX() { return this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET).x; } set _MainTex_STX(x) { var tilOff = this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET); tilOff.x = x; this.tilingOffset = tilOff; } get _MainTex_STY() { return this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET).y; } set _MainTex_STY(y) { var tilOff = this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET); tilOff.y = y; this.tilingOffset = tilOff; } get _MainTex_STZ() { return this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET).z; } set _MainTex_STZ(z) { var tilOff = this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET); tilOff.z = z; this.tilingOffset = tilOff; } get _MainTex_STW() { return this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET).w; } set _MainTex_STW(w) { var tilOff = this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET); tilOff.w = w; this.tilingOffset = tilOff; } get _Cutoff() { return this.alphaTestValue; } set _Cutoff(value) { this.alphaTestValue = value; } get albedoColorR() { return this._ColorR; } set albedoColorR(value) { this._ColorR = value; } get albedoColorG() { return this._ColorG; } set albedoColorG(value) { this._ColorG = value; } get albedoColorB() { return this._ColorB; } set albedoColorB(value) { this._ColorB = value; } get albedoColorA() { return this._ColorA; } set albedoColorA(value) { this._ColorA = value; } get albedoColor() { return this._albedoColor; } set albedoColor(value) { var finalAlbedo = this._shaderValues.getVector(UnlitMaterial.ALBEDOCOLOR); Vector4.scale(value, this._albedoIntensity, finalAlbedo); this._albedoColor = value; this._shaderValues.setVector(UnlitMaterial.ALBEDOCOLOR, finalAlbedo); } get albedoIntensity() { return this._albedoIntensity; } set albedoIntensity(value) { this._AlbedoIntensity = value; } get albedoTexture() { return this._shaderValues.getTexture(UnlitMaterial.ALBEDOTEXTURE); } set albedoTexture(value) { if (value) this._shaderValues.addDefine(UnlitMaterial.SHADERDEFINE_ALBEDOTEXTURE); else this._shaderValues.removeDefine(UnlitMaterial.SHADERDEFINE_ALBEDOTEXTURE); this._shaderValues.setTexture(UnlitMaterial.ALBEDOTEXTURE, value); } get tilingOffsetX() { return this._MainTex_STX; } set tilingOffsetX(x) { this._MainTex_STX = x; } get tilingOffsetY() { return this._MainTex_STY; } set tilingOffsetY(y) { this._MainTex_STY = y; } get tilingOffsetZ() { return this._MainTex_STZ; } set tilingOffsetZ(z) { this._MainTex_STZ = z; } get tilingOffsetW() { return this._MainTex_STW; } set tilingOffsetW(w) { this._MainTex_STW = w; } get tilingOffset() { return this._shaderValues.getVector(UnlitMaterial.TILINGOFFSET); } set tilingOffset(value) { if (value) { if (value.x != 1 || value.y != 1 || value.z != 0 || value.w != 0) this._shaderValues.addDefine(UnlitMaterial.SHADERDEFINE_TILINGOFFSET); else this._shaderValues.removeDefine(UnlitMaterial.SHADERDEFINE_TILINGOFFSET); } else { this._shaderValues.removeDefine(UnlitMaterial.SHADERDEFINE_TILINGOFFSET); } this._shaderValues.setVector(UnlitMaterial.TILINGOFFSET, value); } get enableVertexColor() { return this._enableVertexColor; } set enableVertexColor(value) { this._enableVertexColor = value; if (value) this._shaderValues.addDefine(UnlitMaterial.SHADERDEFINE_ENABLEVERTEXCOLOR); else this._shaderValues.removeDefine(UnlitMaterial.SHADERDEFINE_ENABLEVERTEXCOLOR); } set renderMode(value) { switch (value) { case UnlitMaterial.RENDERMODE_OPAQUE: this.alphaTest = false; this.renderQueue = Material.RENDERQUEUE_OPAQUE; this.depthWrite = true; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_DISABLE; this.depthTest = RenderState.DEPTHTEST_LESS; break; case UnlitMaterial.RENDERMODE_CUTOUT: this.renderQueue = Material.RENDERQUEUE_ALPHATEST; this.alphaTest = true; this.depthWrite = true; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_DISABLE; this.depthTest = RenderState.DEPTHTEST_LESS; break; case UnlitMaterial.RENDERMODE_TRANSPARENT: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.alphaTest = false; this.depthWrite = false; this.cull = RenderState.CULL_BACK; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; this.depthTest = RenderState.DEPTHTEST_LESS; break; default: throw new Error("UnlitMaterial : renderMode value error."); } } get depthWrite() { return this._shaderValues.getBool(UnlitMaterial.DEPTH_WRITE); } set depthWrite(value) { this._shaderValues.setBool(UnlitMaterial.DEPTH_WRITE, value); } get cull() { return this._shaderValues.getInt(UnlitMaterial.CULL); } set cull(value) { this._shaderValues.setInt(UnlitMaterial.CULL, value); } get blend() { return this._shaderValues.getInt(UnlitMaterial.BLEND); } set blend(value) { this._shaderValues.setInt(UnlitMaterial.BLEND, value); } get blendSrc() { return this._shaderValues.getInt(UnlitMaterial.BLEND_SRC); } set blendSrc(value) { this._shaderValues.setInt(UnlitMaterial.BLEND_SRC, value); } get blendDst() { return this._shaderValues.getInt(UnlitMaterial.BLEND_DST); } set blendDst(value) { this._shaderValues.setInt(UnlitMaterial.BLEND_DST, value); } get depthTest() { return this._shaderValues.getInt(UnlitMaterial.DEPTH_TEST); } set depthTest(value) { this._shaderValues.setInt(UnlitMaterial.DEPTH_TEST, value); } clone() { var dest = new UnlitMaterial(); this.cloneTo(dest); return dest; } } UnlitMaterial.RENDERMODE_OPAQUE = 0; UnlitMaterial.RENDERMODE_CUTOUT = 1; UnlitMaterial.RENDERMODE_TRANSPARENT = 2; UnlitMaterial.RENDERMODE_ADDTIVE = 3; UnlitMaterial.ALBEDOTEXTURE = Shader3D.propertyNameToID("u_AlbedoTexture"); UnlitMaterial.ALBEDOCOLOR = Shader3D.propertyNameToID("u_AlbedoColor"); UnlitMaterial.TILINGOFFSET = Shader3D.propertyNameToID("u_TilingOffset"); UnlitMaterial.CULL = Shader3D.propertyNameToID("s_Cull"); UnlitMaterial.BLEND = Shader3D.propertyNameToID("s_Blend"); UnlitMaterial.BLEND_SRC = Shader3D.propertyNameToID("s_BlendSrc"); UnlitMaterial.BLEND_DST = Shader3D.propertyNameToID("s_BlendDst"); UnlitMaterial.DEPTH_TEST = Shader3D.propertyNameToID("s_DepthTest"); UnlitMaterial.DEPTH_WRITE = Shader3D.propertyNameToID("s_DepthWrite"); class WaterPrimaryMaterial extends Material { constructor() { super(); this.setShaderName("WaterPrimary"); this._shaderValues.setVector(WaterPrimaryMaterial.HORIZONCOLOR, new Vector4(0.172, 0.463, 0.435, 0)); this._shaderValues.setNumber(WaterPrimaryMaterial.WAVESCALE, 0.15); this._shaderValues.setVector(WaterPrimaryMaterial.WAVESPEED, new Vector4(19, 9, -16, -7)); } static __initDefine__() { WaterPrimaryMaterial.SHADERDEFINE_MAINTEXTURE = Shader3D.getDefineByName("MAINTEXTURE"); WaterPrimaryMaterial.SHADERDEFINE_NORMALTEXTURE = Shader3D.getDefineByName("NORMALTEXTURE"); } get horizonColor() { return this._shaderValues.getVector(WaterPrimaryMaterial.HORIZONCOLOR); } set horizonColor(value) { this._shaderValues.setVector(WaterPrimaryMaterial.HORIZONCOLOR, value); } get mainTexture() { return this._shaderValues.getTexture(WaterPrimaryMaterial.MAINTEXTURE); } set mainTexture(value) { if (value) this._shaderValues.addDefine(WaterPrimaryMaterial.SHADERDEFINE_MAINTEXTURE); else this._shaderValues.removeDefine(WaterPrimaryMaterial.SHADERDEFINE_MAINTEXTURE); this._shaderValues.setTexture(WaterPrimaryMaterial.MAINTEXTURE, value); } get normalTexture() { return this._shaderValues.getTexture(WaterPrimaryMaterial.NORMALTEXTURE); } set normalTexture(value) { if (value) this._shaderValues.addDefine(WaterPrimaryMaterial.SHADERDEFINE_NORMALTEXTURE); else this._shaderValues.removeDefine(WaterPrimaryMaterial.SHADERDEFINE_NORMALTEXTURE); this._shaderValues.setTexture(WaterPrimaryMaterial.NORMALTEXTURE, value); } get waveScale() { return this._shaderValues.getNumber(WaterPrimaryMaterial.WAVESCALE); } set waveScale(value) { this._shaderValues.setNumber(WaterPrimaryMaterial.WAVESCALE, value); } get waveSpeed() { return this._shaderValues.getVector(WaterPrimaryMaterial.WAVESPEED); } set waveSpeed(value) { this._shaderValues.setVector(WaterPrimaryMaterial.WAVESPEED, value); } clone() { var dest = new WaterPrimaryMaterial(); this.cloneTo(dest); return dest; } } WaterPrimaryMaterial.HORIZONCOLOR = Shader3D.propertyNameToID("u_HorizonColor"); WaterPrimaryMaterial.MAINTEXTURE = Shader3D.propertyNameToID("u_MainTexture"); WaterPrimaryMaterial.NORMALTEXTURE = Shader3D.propertyNameToID("u_NormalTexture"); WaterPrimaryMaterial.WAVESCALE = Shader3D.propertyNameToID("u_WaveScale"); WaterPrimaryMaterial.WAVESPEED = Shader3D.propertyNameToID("u_WaveSpeed"); class MeshSprite3DShaderDeclaration { } class MeshRenderer extends BaseRender { constructor(owner) { super(owner); this._revertStaticBatchDefineUV1 = false; this._projectionViewWorldMatrix = new Matrix4x4(); } _createRenderElement() { return new SubMeshRenderElement(); } _onMeshChange(mesh) { if (mesh) { var count = mesh.subMeshCount; this._renderElements.length = count; for (var i = 0; i < count; i++) { var renderElement = this._renderElements[i]; if (!renderElement) { var material = this.sharedMaterials[i]; renderElement = this._renderElements[i] = this._createRenderElement(); renderElement.setTransform(this._owner._transform); renderElement.render = this; renderElement.material = material ? material : BlinnPhongMaterial.defaultMaterial; } renderElement.setGeometry(mesh.getSubMesh(i)); } } else { this._renderElements.length = 0; } this._boundsChange = true; } _calculateBoundingBox() { var sharedMesh = this._owner.meshFilter.sharedMesh; if (sharedMesh) { var worldMat = this._owner.transform.worldMatrix; sharedMesh.bounds._tranform(worldMat, this._bounds); } if (Laya.Render.supportWebGLPlusCulling) { var min = this._bounds.getMin(); var max = this._bounds.getMax(); var buffer = FrustumCulling._cullingBuffer; buffer[this._cullingBufferIndex + 1] = min.x; buffer[this._cullingBufferIndex + 2] = min.y; buffer[this._cullingBufferIndex + 3] = min.z; buffer[this._cullingBufferIndex + 4] = max.x; buffer[this._cullingBufferIndex + 5] = max.y; buffer[this._cullingBufferIndex + 6] = max.z; } } _needRender(boundFrustum, context) { if (boundFrustum) return boundFrustum.intersects(this.bounds._getBoundBox()); else return true; } _renderUpdate(context, transform) { this._applyLightMapParams(); var element = context.renderElement; switch (element.renderType) { case RenderElement.RENDERTYPE_NORMAL: this._shaderValues.setMatrix4x4(Sprite3D.WORLDMATRIX, transform.worldMatrix); break; case RenderElement.RENDERTYPE_STATICBATCH: if (transform) this._shaderValues.setMatrix4x4(Sprite3D.WORLDMATRIX, transform.worldMatrix); else this._shaderValues.setMatrix4x4(Sprite3D.WORLDMATRIX, Matrix4x4.DEFAULT); if (!this._shaderValues.hasDefine(MeshSprite3DShaderDeclaration.SHADERDEFINE_UV1)) { this._shaderValues.addDefine(MeshSprite3DShaderDeclaration.SHADERDEFINE_UV1); this._revertStaticBatchDefineUV1 = true; } else { this._revertStaticBatchDefineUV1 = false; } this._shaderValues.setVector(RenderableSprite3D.LIGHTMAPSCALEOFFSET, BaseRender._defaultLightmapScaleOffset); break; case RenderElement.RENDERTYPE_VERTEXBATCH: this._shaderValues.setMatrix4x4(Sprite3D.WORLDMATRIX, Matrix4x4.DEFAULT); break; case RenderElement.RENDERTYPE_INSTANCEBATCH: var worldMatrixData = SubMeshInstanceBatch.instance.instanceWorldMatrixData; var insBatches = element.instanceBatchElementList; var elements = insBatches.elements; var count = insBatches.length; for (var i = 0; i < count; i++) worldMatrixData.set(elements[i]._transform.worldMatrix.elements, i * 16); var worldBuffer = SubMeshInstanceBatch.instance.instanceWorldMatrixBuffer; worldBuffer.orphanStorage(); worldBuffer.setData(worldMatrixData.buffer, 0, 0, count * 16 * 4); this._shaderValues.addDefine(MeshSprite3DShaderDeclaration.SHADERDEFINE_GPU_INSTANCE); break; } } _renderUpdateWithCamera(context, transform) { var projectionView = context.projectionViewMatrix; if (projectionView) { var element = context.renderElement; switch (element.renderType) { case RenderElement.RENDERTYPE_NORMAL: case RenderElement.RENDERTYPE_STATICBATCH: case RenderElement.RENDERTYPE_VERTEXBATCH: if (transform) { Matrix4x4.multiply(projectionView, transform.worldMatrix, this._projectionViewWorldMatrix); this._shaderValues.setMatrix4x4(Sprite3D.MVPMATRIX, this._projectionViewWorldMatrix); } else { this._shaderValues.setMatrix4x4(Sprite3D.MVPMATRIX, projectionView); } break; case RenderElement.RENDERTYPE_INSTANCEBATCH: var mvpMatrixData = SubMeshInstanceBatch.instance.instanceMVPMatrixData; var insBatches = element.instanceBatchElementList; var elements = insBatches.elements; var count = insBatches.length; for (var i = 0; i < count; i++) { var worldMat = elements[i]._transform.worldMatrix; Utils3D.mulMatrixByArray(projectionView.elements, 0, worldMat.elements, 0, mvpMatrixData, i * 16); } var mvpBuffer = SubMeshInstanceBatch.instance.instanceMVPMatrixBuffer; mvpBuffer.orphanStorage(); mvpBuffer.setData(mvpMatrixData.buffer, 0, 0, count * 16 * 4); break; } } } _revertBatchRenderUpdate(context) { var element = context.renderElement; switch (element.renderType) { case RenderElement.RENDERTYPE_STATICBATCH: if (this._revertStaticBatchDefineUV1) this._shaderValues.removeDefine(MeshSprite3DShaderDeclaration.SHADERDEFINE_UV1); this._shaderValues.setVector(RenderableSprite3D.LIGHTMAPSCALEOFFSET, this.lightmapScaleOffset); break; case RenderElement.RENDERTYPE_INSTANCEBATCH: this._shaderValues.removeDefine(MeshSprite3DShaderDeclaration.SHADERDEFINE_GPU_INSTANCE); break; } } _destroy() { (this._isPartOfStaticBatch) && (MeshRenderStaticBatchManager.instance._removeRenderSprite(this._owner)); super._destroy(); } } class MeshFilter { constructor(owner) { this._owner = owner; } get sharedMesh() { return this._sharedMesh; } set sharedMesh(value) { if (this._sharedMesh !== value) { var defineDatas = this._owner._render._shaderValues; var lastValue = this._sharedMesh; if (lastValue) { lastValue._removeReference(); this._getMeshDefine(lastValue, MeshFilter._meshVerticeDefine); for (var i = 0, n = MeshFilter._meshVerticeDefine.length; i < n; i++) defineDatas.removeDefine(MeshFilter._meshVerticeDefine[i]); } if (value) { value._addReference(); this._getMeshDefine(value, MeshFilter._meshVerticeDefine); for (var i = 0, n = MeshFilter._meshVerticeDefine.length; i < n; i++) defineDatas.addDefine(MeshFilter._meshVerticeDefine[i]); } this._owner._render._onMeshChange(value); this._sharedMesh = value; } } _getMeshDefine(mesh, out) { out.length = 0; var define; for (var i = 0, n = mesh._subMeshes.length; i < n; i++) { var subMesh = mesh.getSubMesh(i); var vertexElements = subMesh._vertexBuffer._vertexDeclaration._vertexElements; for (var j = 0, m = vertexElements.length; j < m; j++) { var vertexElement = vertexElements[j]; var name = vertexElement._elementUsage; switch (name) { case VertexMesh.MESH_COLOR0: out.push(MeshSprite3DShaderDeclaration.SHADERDEFINE_COLOR); break; case VertexMesh.MESH_TEXTURECOORDINATE0: out.push(MeshSprite3DShaderDeclaration.SHADERDEFINE_UV0); break; case VertexMesh.MESH_TEXTURECOORDINATE1: out.push(MeshSprite3DShaderDeclaration.SHADERDEFINE_UV1); break; } } } return define; } destroy() { this._owner = null; (this._sharedMesh) && (this._sharedMesh._removeReference(), this._sharedMesh = null); } } MeshFilter._meshVerticeDefine = []; class SubMeshDynamicBatch extends GeometryElement { constructor() { super(); this._bufferState = new BufferState(); var gl = Laya.LayaGL.instance; var maxVerDec = VertexMesh.getVertexDeclaration("POSITION,NORMAL,COLOR,UV,UV1,TANGENT"); var maxByteCount = maxVerDec.vertexStride * SubMeshDynamicBatch.maxIndicesCount; this._vertices = new Float32Array(maxByteCount / 4); this._vertexBuffer = new VertexBuffer3D(maxByteCount, gl.DYNAMIC_DRAW); this._indices = new Int16Array(SubMeshDynamicBatch.maxIndicesCount); this._indexBuffer = new IndexBuffer3D(exports.IndexFormat.UInt16, this._indices.length, gl.DYNAMIC_DRAW); var memorySize = this._vertexBuffer._byteLength + this._indexBuffer._byteLength; Laya.Resource._addMemory(memorySize, memorySize); } static __init__() { SubMeshDynamicBatch.instance = new SubMeshDynamicBatch(); } _getBatchVertices(vertexDeclaration, batchVertices, batchOffset, transform, element, subMesh) { var vertexFloatCount = vertexDeclaration.vertexStride / 4; var oriVertexes = subMesh._vertexBuffer.getFloat32Data(); var lightmapScaleOffset = element.render.lightmapScaleOffset; var multiSubMesh = element._dynamicMultiSubMesh; var vertexCount = element._dynamicVertexCount; element._computeWorldPositionsAndNormals(this._positionOffset, this._normalOffset, multiSubMesh, vertexCount); var worldPositions = element._dynamicWorldPositions; var worldNormals = element._dynamicWorldNormals; var indices = subMesh._indices; for (var i = 0; i < vertexCount; i++) { var index = multiSubMesh ? indices[i] : i; var oriOffset = index * vertexFloatCount; var bakeOffset = (i + batchOffset) * vertexFloatCount; var oriOff = i * 3; var bakOff = bakeOffset + this._positionOffset; batchVertices[bakOff] = worldPositions[oriOff]; batchVertices[bakOff + 1] = worldPositions[oriOff + 1]; batchVertices[bakOff + 2] = worldPositions[oriOff + 2]; if (this._normalOffset !== -1) { bakOff = bakeOffset + this._normalOffset; batchVertices[bakOff] = worldNormals[oriOff]; batchVertices[bakOff + 1] = worldNormals[oriOff + 1]; batchVertices[bakOff + 2] = worldNormals[oriOff + 2]; } if (this._colorOffset !== -1) { bakOff = bakeOffset + this._colorOffset; oriOff = oriOffset + this._colorOffset; batchVertices[bakOff] = oriVertexes[oriOff]; batchVertices[bakOff + 1] = oriVertexes[oriOff + 1]; batchVertices[bakOff + 2] = oriVertexes[oriOff + 2]; batchVertices[bakOff + 3] = oriVertexes[oriOff + 3]; } if (this._uv0Offset !== -1) { bakOff = bakeOffset + this._uv0Offset; oriOff = oriOffset + this._uv0Offset; batchVertices[bakOff] = oriVertexes[oriOff]; batchVertices[bakOff + 1] = oriVertexes[oriOff + 1]; } if (this._sTangentOffset !== -1) { bakOff = bakeOffset + this._sTangentOffset; oriOff = oriOffset + this._sTangentOffset; batchVertices[bakOff] = oriVertexes[oriOff]; batchVertices[bakOff + 1] = oriVertexes[oriOff + 1]; batchVertices[bakOff + 2] = oriVertexes[oriOff + 2]; batchVertices[bakOff + 3] = oriVertexes[oriOff + 3]; bakOff = bakeOffset + this._sTangentOffset; oriOff = oriOffset + this._sTangentOffset; batchVertices[bakOff] = oriVertexes[oriOff]; batchVertices[bakOff + 1] = oriVertexes[oriOff + 1]; batchVertices[bakOff + 2] = oriVertexes[oriOff + 2]; batchVertices[bakOff + 3] = oriVertexes[oriOff + 3]; } } } _getBatchIndices(batchIndices, batchIndexCount, batchVertexCount, transform, subMesh, multiSubMesh) { var subIndices = subMesh._indices; var k, m, batchOffset; var isInvert = transform._isFrontFaceInvert; if (multiSubMesh) { if (isInvert) { for (k = 0, m = subIndices.length; k < m; k += 3) { batchOffset = batchIndexCount + k; var index = batchVertexCount + k; batchIndices[batchOffset] = index; batchIndices[batchOffset + 1] = index + 2; batchIndices[batchOffset + 2] = index + 1; } } else { for (k = 0, m = subIndices.length; k < m; k += 3) { batchOffset = batchIndexCount + k; index = batchVertexCount + k; batchIndices[batchOffset] = index; batchIndices[batchOffset + 1] = index + 1; batchIndices[batchOffset + 2] = index + 2; } } } else { if (isInvert) { for (k = 0, m = subIndices.length; k < m; k += 3) { batchOffset = batchIndexCount + k; batchIndices[batchOffset] = batchVertexCount + subIndices[k]; batchIndices[batchOffset + 1] = batchVertexCount + subIndices[k + 2]; batchIndices[batchOffset + 2] = batchVertexCount + subIndices[k + 1]; } } else { for (k = 0, m = subIndices.length; k < m; k += 3) { batchOffset = batchIndexCount + k; batchIndices[batchOffset] = batchVertexCount + subIndices[k]; batchIndices[batchOffset + 1] = batchVertexCount + subIndices[k + 1]; batchIndices[batchOffset + 2] = batchVertexCount + subIndices[k + 2]; } } } } _flush(vertexCount, indexCount) { var gl = Laya.LayaGL.instance; this._vertexBuffer.setData(this._vertices.buffer, 0, 0, vertexCount * (this._bufferState.vertexDeclaration.vertexStride)); this._indexBuffer.setData(this._indices, 0, 0, indexCount); gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, 0); } _prepareRender(state) { var element = state.renderElement; var vertexDeclaration = element.vertexBatchVertexDeclaration; this._bufferState = ILaya3D.MeshRenderDynamicBatchManager.instance._getBufferState(vertexDeclaration); this._positionOffset = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_POSITION0)._offset / 4; var normalElement = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_NORMAL0); this._normalOffset = normalElement ? normalElement._offset / 4 : -1; var colorElement = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_COLOR0); this._colorOffset = colorElement ? colorElement._offset / 4 : -1; var uv0Element = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_TEXTURECOORDINATE0); this._uv0Offset = uv0Element ? uv0Element._offset / 4 : -1; var uv1Element = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_TEXTURECOORDINATE1); this._uv1Offset = uv1Element ? uv1Element._offset / 4 : -1; var tangentElement = vertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_TANGENT0); this._sTangentOffset = tangentElement ? tangentElement._offset / 4 : -1; return true; } _render(context) { this._bufferState.bind(); var element = context.renderElement; var vertexDeclaration = element.vertexBatchVertexDeclaration; var batchElements = element.vertexBatchElementList; var batchVertexCount = 0; var batchIndexCount = 0; var floatStride = vertexDeclaration.vertexStride / 4; var renderBatchCount = 0; var elementCount = batchElements.length; var elements = batchElements.elements; for (var i = 0; i < elementCount; i++) { var subElement = elements[i]; var subMesh = subElement._geometry; var indexCount = subMesh._indexCount; if (batchIndexCount + indexCount > SubMeshDynamicBatch.maxIndicesCount) { this._flush(batchVertexCount, batchIndexCount); renderBatchCount++; Laya.Stat.trianglesFaces += batchIndexCount / 3; batchVertexCount = batchIndexCount = 0; } var transform = subElement._transform; this._getBatchVertices(vertexDeclaration, this._vertices, batchVertexCount, transform, subElement, subMesh); this._getBatchIndices(this._indices, batchIndexCount, batchVertexCount, transform, subMesh, subElement._dynamicMultiSubMesh); batchVertexCount += subElement._dynamicVertexCount; batchIndexCount += indexCount; } this._flush(batchVertexCount, batchIndexCount); renderBatchCount++; Laya.Stat.renderBatches += renderBatchCount; Laya.Stat.savedRenderBatches += elementCount - renderBatchCount; Laya.Stat.trianglesFaces += batchIndexCount / 3; } } SubMeshDynamicBatch.maxAllowVertexCount = 10; SubMeshDynamicBatch.maxAllowAttribueCount = 900; SubMeshDynamicBatch.maxIndicesCount = 32000; class MeshRenderDynamicBatchManager extends DynamicBatchManager { constructor() { super(); this._instanceBatchOpaqueMarks = []; this._vertexBatchOpaqueMarks = []; this._cacheBufferStates = []; this._updateCountMark = 0; } getInstanceBatchOpaquaMark(receiveShadow, materialID, subMeshID, invertFace) { var instanceReceiveShadowMarks = (this._instanceBatchOpaqueMarks[receiveShadow ? 0 : 1]) || (this._instanceBatchOpaqueMarks[receiveShadow ? 0 : 1] = []); var instanceMaterialMarks = (instanceReceiveShadowMarks[materialID]) || (instanceReceiveShadowMarks[materialID] = []); var instancSubMeshMarks = (instanceMaterialMarks[subMeshID]) || (instanceMaterialMarks[subMeshID] = []); return instancSubMeshMarks[invertFace ? 1 : 0] || (instancSubMeshMarks[invertFace ? 1 : 0] = new BatchMark()); } getVertexBatchOpaquaMark(lightMapIndex, receiveShadow, materialID, verDecID) { var dynLightMapMarks = (this._vertexBatchOpaqueMarks[lightMapIndex]) || (this._vertexBatchOpaqueMarks[lightMapIndex] = []); var dynReceiveShadowMarks = (dynLightMapMarks[receiveShadow ? 0 : 1]) || (dynLightMapMarks[receiveShadow ? 0 : 1] = []); var dynMaterialMarks = (dynReceiveShadowMarks[materialID]) || (dynReceiveShadowMarks[materialID] = []); return dynMaterialMarks[verDecID] || (dynMaterialMarks[verDecID] = new BatchMark()); } _getBufferState(vertexDeclaration) { var bufferState = this._cacheBufferStates[vertexDeclaration.id]; if (!bufferState) { var instance = SubMeshDynamicBatch.instance; bufferState = new BufferState(); bufferState.bind(); var vertexBuffer = instance._vertexBuffer; vertexBuffer.vertexDeclaration = vertexDeclaration; bufferState.applyVertexBuffer(vertexBuffer); bufferState.applyIndexBuffer(instance._indexBuffer); bufferState.unBind(); this._cacheBufferStates[vertexDeclaration.id] = bufferState; } return bufferState; } _getBatchRenderElementFromPool() { var renderElement = this._batchRenderElementPool[this._batchRenderElementPoolIndex++]; if (!renderElement) { renderElement = new SubMeshRenderElement(); this._batchRenderElementPool[this._batchRenderElementPoolIndex - 1] = renderElement; renderElement.vertexBatchElementList = new SingletonList(); renderElement.instanceBatchElementList = new SingletonList(); } return renderElement; } _clear() { super._clear(); this._updateCountMark++; } } MeshRenderDynamicBatchManager.instance = new MeshRenderDynamicBatchManager(); class MeshSprite3D extends RenderableSprite3D { constructor(mesh = null, name = null) { super(name); this._meshFilter = new MeshFilter(this); this._render = new MeshRenderer(this); (mesh) && (this._meshFilter.sharedMesh = mesh); } static __init__() { MeshSprite3DShaderDeclaration.SHADERDEFINE_UV0 = Shader3D.getDefineByName("UV"); MeshSprite3DShaderDeclaration.SHADERDEFINE_COLOR = Shader3D.getDefineByName("COLOR"); MeshSprite3DShaderDeclaration.SHADERDEFINE_UV1 = Shader3D.getDefineByName("UV1"); MeshSprite3DShaderDeclaration.SHADERDEFINE_GPU_INSTANCE = Shader3D.getDefineByName("GPU_INSTANCE"); StaticBatchManager._registerManager(MeshRenderStaticBatchManager.instance); DynamicBatchManager._registerManager(MeshRenderDynamicBatchManager.instance); } get meshFilter() { return this._meshFilter; } get meshRenderer() { return this._render; } _parse(data, spriteMap) { super._parse(data, spriteMap); var render = this.meshRenderer; var lightmapIndex = data.lightmapIndex; (lightmapIndex != null) && (render.lightmapIndex = lightmapIndex); var lightmapScaleOffsetArray = data.lightmapScaleOffset; (lightmapScaleOffsetArray) && (render.lightmapScaleOffset = new Vector4(lightmapScaleOffsetArray[0], lightmapScaleOffsetArray[1], lightmapScaleOffsetArray[2], lightmapScaleOffsetArray[3])); (data.meshPath != undefined) && (this.meshFilter.sharedMesh = Laya.Loader.getRes(data.meshPath)); (data.enableRender != undefined) && (render.enable = data.enableRender); (data.receiveShadows != undefined) && (render.receiveShadow = data.receiveShadows); (data.castShadow != undefined) && (render.castShadow = data.castShadow); var materials = data.materials; if (materials) { var sharedMaterials = render.sharedMaterials; var materialCount = materials.length; sharedMaterials.length = materialCount; for (var i = 0; i < materialCount; i++) { sharedMaterials[i] = Laya.Loader.getRes(materials[i].path); } render.sharedMaterials = sharedMaterials; } } _addToInitStaticBatchManager() { if (this.meshFilter.sharedMesh) MeshRenderStaticBatchManager.instance._addBatchSprite(this); } _cloneTo(destObject, rootSprite, dstSprite) { var meshSprite3D = destObject; meshSprite3D._meshFilter.sharedMesh = this._meshFilter.sharedMesh; var meshRender = this._render; var destMeshRender = meshSprite3D._render; destMeshRender.enable = meshRender.enable; destMeshRender.sharedMaterials = meshRender.sharedMaterials; destMeshRender.castShadow = meshRender.castShadow; var lightmapScaleOffset = meshRender.lightmapScaleOffset; lightmapScaleOffset && (destMeshRender.lightmapScaleOffset = lightmapScaleOffset.clone()); destMeshRender.lightmapIndex = meshRender.lightmapIndex; destMeshRender.receiveShadow = meshRender.receiveShadow; destMeshRender.sortingFudge = meshRender.sortingFudge; super._cloneTo(destObject, rootSprite, dstSprite); } destroy(destroyChild = true) { if (this.destroyed) return; super.destroy(destroyChild); this._meshFilter.destroy(); } _create() { return new MeshSprite3D(); } } class GradientMode { } GradientMode.Blend = 0; GradientMode.Fixed = 1; class Gradient { constructor(maxColorRGBKeyCount, maxColorAlphaKeyCount) { this._mode = 0; this._maxColorRGBKeysCount = 0; this._maxColorAlphaKeysCount = 0; this._colorRGBKeysCount = 0; this._colorAlphaKeysCount = 0; this._alphaElements = null; this._rgbElements = null; this._maxColorRGBKeysCount = maxColorRGBKeyCount; this._maxColorAlphaKeysCount = maxColorAlphaKeyCount; this._rgbElements = new Float32Array(maxColorRGBKeyCount * 4); this._alphaElements = new Float32Array(maxColorAlphaKeyCount * 2); } get mode() { return this._mode; } set mode(value) { this._mode = value; } get colorRGBKeysCount() { return this._colorRGBKeysCount; } get colorAlphaKeysCount() { return this._colorAlphaKeysCount; } get maxColorRGBKeysCount() { return this._maxColorRGBKeysCount; } get maxColorAlphaKeysCount() { return this._maxColorAlphaKeysCount; } addColorRGB(key, value) { if (this._colorRGBKeysCount < this._maxColorRGBKeysCount) { var offset = this._colorRGBKeysCount * 4; this._rgbElements[offset] = key; this._rgbElements[offset + 1] = value.r; this._rgbElements[offset + 2] = value.g; this._rgbElements[offset + 3] = value.b; this._colorRGBKeysCount++; } else { console.warn("Gradient:warning:data count must lessEqual than " + this._maxColorRGBKeysCount); } } addColorAlpha(key, value) { if (this._colorAlphaKeysCount < this._maxColorAlphaKeysCount) { var offset = this._colorAlphaKeysCount * 2; this._alphaElements[offset] = key; this._alphaElements[offset + 1] = value; this._colorAlphaKeysCount++; } else { console.warn("Gradient:warning:data count must lessEqual than " + this._maxColorAlphaKeysCount); } } updateColorRGB(index, key, value) { if (index < this._colorRGBKeysCount) { var offset = index * 4; this._rgbElements[offset] = key; this._rgbElements[offset + 1] = value.r; this._rgbElements[offset + 2] = value.g; this._rgbElements[offset + 3] = value.b; } else { console.warn("Gradient:warning:index must lessEqual than colorRGBKeysCount:" + this._colorRGBKeysCount); } } updateColorAlpha(index, key, value) { if (index < this._colorAlphaKeysCount) { var offset = index * 2; this._alphaElements[offset] = key; this._alphaElements[offset + 1] = value; } else { console.warn("Gradient:warning:index must lessEqual than colorAlphaKeysCount:" + this._colorAlphaKeysCount); } } evaluateColorRGB(lerpFactor, out, startSearchIndex = 0, reverseSearch = false) { lerpFactor = Math.min(Math.max(lerpFactor, 0.0), 1.0); var rgbElements = this._rgbElements; var curIndex = startSearchIndex; if (reverseSearch) { for (var i = curIndex; i >= 0; i--) { var offset = i * 4; var left = rgbElements[offset]; if (lerpFactor === left) { out.r = rgbElements[offset + 1]; out.g = rgbElements[offset + 2]; out.b = rgbElements[offset + 3]; return curIndex; } switch (this._mode) { case GradientMode.Blend: if (lerpFactor > left) { var right = rgbElements[offset + 4]; if (lerpFactor > right) throw "Gradient:wrong startSearchIndex."; var diff = right - left; var y1 = right - lerpFactor; var y2 = lerpFactor - left; out.r = (y1 * rgbElements[offset + 1] + y2 * rgbElements[offset + 5]) / diff; out.g = (y1 * rgbElements[offset + 2] + y2 * rgbElements[offset + 6]) / diff; out.b = (y1 * rgbElements[offset + 3] + y2 * rgbElements[offset + 7]) / diff; return curIndex; } else { curIndex--; continue; } case GradientMode.Fixed: if (lerpFactor > left) { if (lerpFactor > rgbElements[offset + 4]) throw "Gradient:wrong startSearchIndex."; out.r = rgbElements[offset + 5]; out.g = rgbElements[offset + 6]; out.b = rgbElements[offset + 7]; return curIndex; } else { curIndex--; continue; } default: throw "Gradient:unknown mode."; } } } else { for (var i = 0, n = this._rgbElements.length; i < n; i++) { offset = i * 4; var right = rgbElements[offset]; if (lerpFactor === right) { out.r = rgbElements[offset + 1]; out.g = rgbElements[offset + 2]; out.b = rgbElements[offset + 3]; return curIndex; } switch (this._mode) { case GradientMode.Blend: if (lerpFactor < right) { var left = rgbElements[offset - 4]; if (lerpFactor < left) throw "Gradient:wrong startSearchIndex."; var diff = right - left; var y1 = right - lerpFactor; var y2 = lerpFactor - left; out.r = (y1 * rgbElements[offset - 3] + y2 * rgbElements[offset + 1]) / diff; out.g = (y1 * rgbElements[offset - 2] + y2 * rgbElements[offset + 2]) / diff; out.b = (y1 * rgbElements[offset - 1] + y2 * rgbElements[offset + 3]) / diff; return curIndex; } else { curIndex++; continue; } case GradientMode.Fixed: if (lerpFactor < right) { if (lerpFactor < rgbElements[offset - 4]) throw "Gradient:wrong startSearchIndex."; out.r = rgbElements[offset + 1]; out.g = rgbElements[offset + 2]; out.b = rgbElements[offset + 3]; return curIndex; } else { curIndex++; continue; } default: throw "Gradient:unknown mode."; } } } return curIndex; } evaluateColorAlpha(lerpFactor, outColor, startSearchIndex = 0, reverseSearch = false) { lerpFactor = Math.min(Math.max(lerpFactor, 0.0), 1.0); var alphaElements = this._alphaElements; var curIndex = startSearchIndex; if (reverseSearch) { for (var i = curIndex; i >= 0; i--) { var offset = i * 2; var left = alphaElements[offset]; if (lerpFactor === left) { outColor.a = alphaElements[offset + 1]; return curIndex; } switch (this._mode) { case GradientMode.Blend: if (lerpFactor > left) { var right = alphaElements[offset + 2]; if (lerpFactor > right) throw "Gradient:wrong startSearchIndex."; var diff = right - left; var x1 = right - lerpFactor; var x2 = lerpFactor - left; outColor.a = (x1 * alphaElements[offset + 1] + x2 * alphaElements[offset + 3]) / diff; return curIndex; } else { curIndex--; continue; } case GradientMode.Fixed: if (lerpFactor > left) { if (lerpFactor > alphaElements[offset + 2]) throw "Gradient:wrong startSearchIndex."; outColor.a = alphaElements[offset + 3]; return curIndex; } else { curIndex--; continue; } default: throw "Gradient:unknown mode."; } } } else { for (var i = curIndex, n = this._alphaElements.length; i < n; i++) { var offset = i * 2; var right = alphaElements[offset]; if (lerpFactor === right) { outColor.a = alphaElements[offset + 1]; return curIndex; } switch (this._mode) { case GradientMode.Blend: if (lerpFactor < right) { var left = alphaElements[offset - 2]; if (lerpFactor < left) throw "Gradient:wrong startSearchIndex."; var diff = right - left; var x1 = right - lerpFactor; var x2 = lerpFactor - left; outColor.a = (x1 * alphaElements[offset - 1] + x2 * alphaElements[offset + 1]) / diff; return curIndex; } else { curIndex++; continue; } case GradientMode.Fixed: if (lerpFactor < right) { if (lerpFactor < alphaElements[offset - 2]) throw "Gradient:wrong startSearchIndex."; outColor.a = alphaElements[offset + 1]; return curIndex; } else { curIndex++; continue; } default: throw "Gradient:unknown mode."; } } } return curIndex; } cloneTo(destObject) { var destGradientDataColor = destObject; var i, n; destGradientDataColor._colorAlphaKeysCount = this._colorAlphaKeysCount; var destAlphaElements = destGradientDataColor._alphaElements; for (i = 0, n = this._alphaElements.length; i < n; i++) destAlphaElements[i] = this._alphaElements[i]; destGradientDataColor._colorRGBKeysCount = this._colorRGBKeysCount; var destRGBElements = destGradientDataColor._rgbElements; for (i = 0, n = this._rgbElements.length; i < n; i++) destRGBElements[i] = this._rgbElements[i]; } clone() { var destGradientDataColor = new Gradient(this._maxColorRGBKeysCount, this._maxColorAlphaKeysCount); this.cloneTo(destGradientDataColor); return destGradientDataColor; } } class Burst { constructor(time, minCount, maxCount) { this._time = time; this._minCount = minCount; this._maxCount = maxCount; } get time() { return this._time; } get minCount() { return this._minCount; } get maxCount() { return this._maxCount; } cloneTo(destObject) { var destBurst = destObject; destBurst._time = this._time; destBurst._minCount = this._minCount; destBurst._maxCount = this._maxCount; } clone() { var destBurst = new Burst(this._time, this._minCount, this._maxCount); this.cloneTo(destBurst); return destBurst; } } class GradientColor { constructor() { this._type = 0; this._constant = null; this._constantMin = null; this._constantMax = null; this._gradient = null; this._gradientMin = null; this._gradientMax = null; } static createByConstant(constant) { var gradientColor = new GradientColor(); gradientColor._type = 0; gradientColor._constant = constant; return gradientColor; } static createByGradient(gradient) { var gradientColor = new GradientColor(); gradientColor._type = 1; gradientColor._gradient = gradient; return gradientColor; } static createByRandomTwoConstant(minConstant, maxConstant) { var gradientColor = new GradientColor(); gradientColor._type = 2; gradientColor._constantMin = minConstant; gradientColor._constantMax = maxConstant; return gradientColor; } static createByRandomTwoGradient(minGradient, maxGradient) { var gradientColor = new GradientColor(); gradientColor._type = 3; gradientColor._gradientMin = minGradient; gradientColor._gradientMax = maxGradient; return gradientColor; } get type() { return this._type; } get constant() { return this._constant; } get constantMin() { return this._constantMin; } get constantMax() { return this._constantMax; } get gradient() { return this._gradient; } get gradientMin() { return this._gradientMin; } get gradientMax() { return this._gradientMax; } cloneTo(destObject) { var destGradientColor = destObject; destGradientColor._type = this._type; this._constant.cloneTo(destGradientColor._constant); this._constantMin.cloneTo(destGradientColor._constantMin); this._constantMax.cloneTo(destGradientColor._constantMax); this._gradient.cloneTo(destGradientColor._gradient); this._gradientMin.cloneTo(destGradientColor._gradientMin); this._gradientMax.cloneTo(destGradientColor._gradientMax); } clone() { var destGradientColor = new GradientColor(); this.cloneTo(destGradientColor); return destGradientColor; } } class ColorOverLifetime { constructor(color) { this._color = color; } get color() { return this._color; } cloneTo(destObject) { var destColorOverLifetime = destObject; this._color.cloneTo(destColorOverLifetime._color); destColorOverLifetime.enable = this.enable; } clone() { var destColor; switch (this._color.type) { case 0: destColor = GradientColor.createByConstant(this._color.constant.clone()); break; case 1: destColor = GradientColor.createByGradient(this._color.gradient.clone()); break; case 2: destColor = GradientColor.createByRandomTwoConstant(this._color.constantMin.clone(), this._color.constantMax.clone()); break; case 3: destColor = GradientColor.createByRandomTwoGradient(this._color.gradientMin.clone(), this._color.gradientMax.clone()); break; } var destColorOverLifetime = new ColorOverLifetime(destColor); destColorOverLifetime.enable = this.enable; return destColorOverLifetime; } } class FrameOverTime { constructor() { this._type = 0; this._constant = 0; this._overTime = null; this._constantMin = 0; this._constantMax = 0; this._overTimeMin = null; this._overTimeMax = null; } static createByConstant(constant = 0) { var rotationOverLifetime = new FrameOverTime(); rotationOverLifetime._type = 0; rotationOverLifetime._constant = constant; return rotationOverLifetime; } static createByOverTime(overTime) { var rotationOverLifetime = new FrameOverTime(); rotationOverLifetime._type = 1; rotationOverLifetime._overTime = overTime; return rotationOverLifetime; } static createByRandomTwoConstant(constantMin = 0, constantMax = 0) { var rotationOverLifetime = new FrameOverTime(); rotationOverLifetime._type = 2; rotationOverLifetime._constantMin = constantMin; rotationOverLifetime._constantMax = constantMax; return rotationOverLifetime; } static createByRandomTwoOverTime(gradientFrameMin, gradientFrameMax) { var rotationOverLifetime = new FrameOverTime(); rotationOverLifetime._type = 3; rotationOverLifetime._overTimeMin = gradientFrameMin; rotationOverLifetime._overTimeMax = gradientFrameMax; return rotationOverLifetime; } get type() { return this._type; } get constant() { return this._constant; } get frameOverTimeData() { return this._overTime; } get constantMin() { return this._constantMin; } get constantMax() { return this._constantMax; } get frameOverTimeDataMin() { return this._overTimeMin; } get frameOverTimeDataMax() { return this._overTimeMax; } cloneTo(destObject) { var destFrameOverTime = destObject; destFrameOverTime._type = this._type; destFrameOverTime._constant = this._constant; (this._overTime) && (this._overTime.cloneTo(destFrameOverTime._overTime)); destFrameOverTime._constantMin = this._constantMin; destFrameOverTime._constantMax = this._constantMax; (this._overTimeMin) && (this._overTimeMin.cloneTo(destFrameOverTime._overTimeMin)); (this._overTimeMax) && (this._overTimeMax.cloneTo(destFrameOverTime._overTimeMax)); } clone() { var destFrameOverTime = new FrameOverTime(); this.cloneTo(destFrameOverTime); return destFrameOverTime; } } class GradientAngularVelocity { constructor() { this._type = 0; this._separateAxes = false; this._constant = 0; this._constantSeparate = null; this._gradient = null; this._gradientX = null; this._gradientY = null; this._gradientZ = null; this._gradientW = null; this._constantMin = 0; this._constantMax = 0; this._constantMinSeparate = null; this._constantMaxSeparate = null; this._gradientMin = null; this._gradientMax = null; this._gradientXMin = null; this._gradientXMax = null; this._gradientYMin = null; this._gradientYMax = null; this._gradientZMin = null; this._gradientZMax = null; this._gradientWMin = null; this._gradientWMax = null; } static createByConstant(constant) { var gradientAngularVelocity = new GradientAngularVelocity(); gradientAngularVelocity._type = 0; gradientAngularVelocity._separateAxes = false; gradientAngularVelocity._constant = constant; return gradientAngularVelocity; } static createByConstantSeparate(separateConstant) { var gradientAngularVelocity = new GradientAngularVelocity(); gradientAngularVelocity._type = 0; gradientAngularVelocity._separateAxes = true; gradientAngularVelocity._constantSeparate = separateConstant; return gradientAngularVelocity; } static createByGradient(gradient) { var gradientAngularVelocity = new GradientAngularVelocity(); gradientAngularVelocity._type = 1; gradientAngularVelocity._separateAxes = false; gradientAngularVelocity._gradient = gradient; return gradientAngularVelocity; } static createByGradientSeparate(gradientX, gradientY, gradientZ) { var gradientAngularVelocity = new GradientAngularVelocity(); gradientAngularVelocity._type = 1; gradientAngularVelocity._separateAxes = true; gradientAngularVelocity._gradientX = gradientX; gradientAngularVelocity._gradientY = gradientY; gradientAngularVelocity._gradientZ = gradientZ; return gradientAngularVelocity; } static createByRandomTwoConstant(constantMin, constantMax) { var gradientAngularVelocity = new GradientAngularVelocity(); gradientAngularVelocity._type = 2; gradientAngularVelocity._separateAxes = false; gradientAngularVelocity._constantMin = constantMin; gradientAngularVelocity._constantMax = constantMax; return gradientAngularVelocity; } static createByRandomTwoConstantSeparate(separateConstantMin, separateConstantMax) { var gradientAngularVelocity = new GradientAngularVelocity(); gradientAngularVelocity._type = 2; gradientAngularVelocity._separateAxes = true; gradientAngularVelocity._constantMinSeparate = separateConstantMin; gradientAngularVelocity._constantMaxSeparate = separateConstantMax; return gradientAngularVelocity; } static createByRandomTwoGradient(gradientMin, gradientMax) { var gradientAngularVelocity = new GradientAngularVelocity(); gradientAngularVelocity._type = 3; gradientAngularVelocity._separateAxes = false; gradientAngularVelocity._gradientMin = gradientMin; gradientAngularVelocity._gradientMax = gradientMax; return gradientAngularVelocity; } static createByRandomTwoGradientSeparate(gradientXMin, gradientXMax, gradientYMin, gradientYMax, gradientZMin, gradientZMax, gradientWMin, gradientWMax) { var gradientAngularVelocity = new GradientAngularVelocity(); gradientAngularVelocity._type = 3; gradientAngularVelocity._separateAxes = true; gradientAngularVelocity._gradientXMin = gradientXMin; gradientAngularVelocity._gradientXMax = gradientXMax; gradientAngularVelocity._gradientYMin = gradientYMin; gradientAngularVelocity._gradientYMax = gradientYMax; gradientAngularVelocity._gradientZMin = gradientZMin; gradientAngularVelocity._gradientZMax = gradientZMax; gradientAngularVelocity._gradientWMin = gradientWMin; gradientAngularVelocity._gradientWMax = gradientWMax; return gradientAngularVelocity; } get type() { return this._type; } get separateAxes() { return this._separateAxes; } get constant() { return this._constant; } get constantSeparate() { return this._constantSeparate; } get gradient() { return this._gradient; } get gradientX() { return this._gradientX; } get gradientY() { return this._gradientY; } get gradientZ() { return this._gradientZ; } get gradientW() { return this._gradientW; } get constantMin() { return this._constantMin; } get constantMax() { return this._constantMax; } get constantMinSeparate() { return this._constantMinSeparate; } get constantMaxSeparate() { return this._constantMaxSeparate; } get gradientMin() { return this._gradientMin; } get gradientMax() { return this._gradientMax; } get gradientXMin() { return this._gradientXMin; } get gradientXMax() { return this._gradientXMax; } get gradientYMin() { return this._gradientYMin; } get gradientYMax() { return this._gradientYMax; } get gradientZMin() { return this._gradientZMin; } get gradientZMax() { return this._gradientZMax; } get gradientWMin() { return this._gradientWMin; } get gradientWMax() { return this._gradientWMax; } cloneTo(destObject) { var destGradientAngularVelocity = destObject; destGradientAngularVelocity._type = this._type; destGradientAngularVelocity._separateAxes = this._separateAxes; destGradientAngularVelocity._constant = this._constant; this._constantSeparate.cloneTo(destGradientAngularVelocity._constantSeparate); this._gradient.cloneTo(destGradientAngularVelocity._gradient); this._gradientX.cloneTo(destGradientAngularVelocity._gradientX); this._gradientY.cloneTo(destGradientAngularVelocity._gradientY); this._gradientZ.cloneTo(destGradientAngularVelocity._gradientZ); destGradientAngularVelocity._constantMin = this._constantMin; destGradientAngularVelocity._constantMax = this._constantMax; this._constantMinSeparate.cloneTo(destGradientAngularVelocity._constantMinSeparate); this._constantMaxSeparate.cloneTo(destGradientAngularVelocity._constantMaxSeparate); this._gradientMin.cloneTo(destGradientAngularVelocity._gradientMin); this._gradientMax.cloneTo(destGradientAngularVelocity._gradientMax); this._gradientXMin.cloneTo(destGradientAngularVelocity._gradientXMin); this._gradientXMax.cloneTo(destGradientAngularVelocity._gradientXMax); this._gradientYMin.cloneTo(destGradientAngularVelocity._gradientYMin); this._gradientYMax.cloneTo(destGradientAngularVelocity._gradientYMax); this._gradientZMin.cloneTo(destGradientAngularVelocity._gradientZMin); this._gradientZMax.cloneTo(destGradientAngularVelocity._gradientZMax); } clone() { var destGradientAngularVelocity = new GradientAngularVelocity(); this.cloneTo(destGradientAngularVelocity); return destGradientAngularVelocity; } } class GradientDataInt { constructor() { this._currentLength = 0; this._elements = new Float32Array(8); } get gradientCount() { return this._currentLength / 2; } add(key, value) { if (this._currentLength < 8) { if ((this._currentLength === 6) && ((key !== 1))) { key = 1; console.log("Warning:the forth key is be force set to 1."); } this._elements[this._currentLength++] = key; this._elements[this._currentLength++] = value; } else { console.log("Warning:data count must lessEqual than 4"); } } cloneTo(destObject) { var destGradientDataInt = destObject; destGradientDataInt._currentLength = this._currentLength; var destElements = destGradientDataInt._elements; for (var i = 0, n = this._elements.length; i < n; i++) { destElements[i] = this._elements[i]; } } clone() { var destGradientDataInt = new GradientDataInt(); this.cloneTo(destGradientDataInt); return destGradientDataInt; } } class GradientDataNumber { constructor() { this._currentLength = 0; this._elements = new Float32Array(8); } get gradientCount() { return this._currentLength / 2; } add(key, value) { if (this._currentLength < 8) { if ((this._currentLength === 6) && ((key !== 1))) { key = 1; console.log("GradientDataNumber warning:the forth key is be force set to 1."); } this._elements[this._currentLength++] = key; this._elements[this._currentLength++] = value; } else { console.log("GradientDataNumber warning:data count must lessEqual than 4"); } } getKeyByIndex(index) { return this._elements[index * 2]; } getValueByIndex(index) { return this._elements[index * 2 + 1]; } getAverageValue() { var total = 0; for (var i = 0, n = this._currentLength - 2; i < n; i += 2) { var subValue = this._elements[i + 1]; subValue += this._elements[i + 3]; subValue = subValue * (this._elements[i + 2] - this._elements[i]); } return total / 2; } cloneTo(destObject) { var destGradientDataNumber = destObject; destGradientDataNumber._currentLength = this._currentLength; var destElements = destGradientDataNumber._elements; for (var i = 0, n = this._elements.length; i < n; i++) destElements[i] = this._elements[i]; } clone() { var destGradientDataNumber = new GradientDataNumber(); this.cloneTo(destGradientDataNumber); return destGradientDataNumber; } } class GradientSize { constructor() { this._type = 0; this._separateAxes = false; this._gradient = null; this._gradientX = null; this._gradientY = null; this._gradientZ = null; this._constantMin = 0; this._constantMax = 0; this._constantMinSeparate = null; this._constantMaxSeparate = null; this._gradientMin = null; this._gradientMax = null; this._gradientXMin = null; this._gradientXMax = null; this._gradientYMin = null; this._gradientYMax = null; this._gradientZMin = null; this._gradientZMax = null; } static createByGradient(gradient) { var gradientSize = new GradientSize(); gradientSize._type = 0; gradientSize._separateAxes = false; gradientSize._gradient = gradient; return gradientSize; } static createByGradientSeparate(gradientX, gradientY, gradientZ) { var gradientSize = new GradientSize(); gradientSize._type = 0; gradientSize._separateAxes = true; gradientSize._gradientX = gradientX; gradientSize._gradientY = gradientY; gradientSize._gradientZ = gradientZ; return gradientSize; } static createByRandomTwoConstant(constantMin, constantMax) { var gradientSize = new GradientSize(); gradientSize._type = 1; gradientSize._separateAxes = false; gradientSize._constantMin = constantMin; gradientSize._constantMax = constantMax; return gradientSize; } static createByRandomTwoConstantSeparate(constantMinSeparate, constantMaxSeparate) { var gradientSize = new GradientSize(); gradientSize._type = 1; gradientSize._separateAxes = true; gradientSize._constantMinSeparate = constantMinSeparate; gradientSize._constantMaxSeparate = constantMaxSeparate; return gradientSize; } static createByRandomTwoGradient(gradientMin, gradientMax) { var gradientSize = new GradientSize(); gradientSize._type = 2; gradientSize._separateAxes = false; gradientSize._gradientMin = gradientMin; gradientSize._gradientMax = gradientMax; return gradientSize; } static createByRandomTwoGradientSeparate(gradientXMin, gradientXMax, gradientYMin, gradientYMax, gradientZMin, gradientZMax) { var gradientSize = new GradientSize(); gradientSize._type = 2; gradientSize._separateAxes = true; gradientSize._gradientXMin = gradientXMin; gradientSize._gradientXMax = gradientXMax; gradientSize._gradientYMin = gradientYMin; gradientSize._gradientYMax = gradientYMax; gradientSize._gradientZMin = gradientZMin; gradientSize._gradientZMax = gradientZMax; return gradientSize; } get type() { return this._type; } get separateAxes() { return this._separateAxes; } get gradient() { return this._gradient; } get gradientX() { return this._gradientX; } get gradientY() { return this._gradientY; } get gradientZ() { return this._gradientZ; } get constantMin() { return this._constantMin; } get constantMax() { return this._constantMax; } get constantMinSeparate() { return this._constantMinSeparate; } get constantMaxSeparate() { return this._constantMaxSeparate; } get gradientMin() { return this._gradientMin; } get gradientMax() { return this._gradientMax; } get gradientXMin() { return this._gradientXMin; } get gradientXMax() { return this._gradientXMax; } get gradientYMin() { return this._gradientYMin; } get gradientYMax() { return this._gradientYMax; } get gradientZMin() { return this._gradientZMin; } get gradientZMax() { return this._gradientZMax; } getMaxSizeInGradient() { var i, n; var maxSize = -Number.MAX_VALUE; switch (this._type) { case 0: if (this._separateAxes) { for (i = 0, n = this._gradientX.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradientX.getValueByIndex(i)); for (i = 0, n = this._gradientY.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradientY.getValueByIndex(i)); } else { for (i = 0, n = this._gradient.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradient.getValueByIndex(i)); } break; case 1: if (this._separateAxes) { maxSize = Math.max(this._constantMinSeparate.x, this._constantMaxSeparate.x); maxSize = Math.max(maxSize, this._constantMinSeparate.y); maxSize = Math.max(maxSize, this._constantMaxSeparate.y); } else { maxSize = Math.max(this._constantMin, this._constantMax); } break; case 2: if (this._separateAxes) { for (i = 0, n = this._gradientXMin.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradientXMin.getValueByIndex(i)); for (i = 0, n = this._gradientXMax.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradientXMax.getValueByIndex(i)); for (i = 0, n = this._gradientYMin.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradientYMin.getValueByIndex(i)); for (i = 0, n = this._gradientZMax.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradientZMax.getValueByIndex(i)); } else { for (i = 0, n = this._gradientMin.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradientMin.getValueByIndex(i)); for (i = 0, n = this._gradientMax.gradientCount; i < n; i++) maxSize = Math.max(maxSize, this._gradientMax.getValueByIndex(i)); } break; } return maxSize; } cloneTo(destObject) { var destGradientSize = destObject; destGradientSize._type = this._type; destGradientSize._separateAxes = this._separateAxes; this._gradient.cloneTo(destGradientSize._gradient); this._gradientX.cloneTo(destGradientSize._gradientX); this._gradientY.cloneTo(destGradientSize._gradientY); this._gradientZ.cloneTo(destGradientSize._gradientZ); destGradientSize._constantMin = this._constantMin; destGradientSize._constantMax = this._constantMax; this._constantMinSeparate.cloneTo(destGradientSize._constantMinSeparate); this._constantMaxSeparate.cloneTo(destGradientSize._constantMaxSeparate); this._gradientMin.cloneTo(destGradientSize._gradientMin); this._gradientMax.cloneTo(destGradientSize._gradientMax); this._gradientXMin.cloneTo(destGradientSize._gradientXMin); this._gradientXMax.cloneTo(destGradientSize._gradientXMax); this._gradientYMin.cloneTo(destGradientSize._gradientYMin); this._gradientYMax.cloneTo(destGradientSize._gradientYMax); this._gradientZMin.cloneTo(destGradientSize._gradientZMin); this._gradientZMax.cloneTo(destGradientSize._gradientZMax); } clone() { var destGradientSize = new GradientSize(); this.cloneTo(destGradientSize); return destGradientSize; } } class GradientVelocity { constructor() { this._type = 0; this._constant = null; this._gradientX = null; this._gradientY = null; this._gradientZ = null; this._constantMin = null; this._constantMax = null; this._gradientXMin = null; this._gradientXMax = null; this._gradientYMin = null; this._gradientYMax = null; this._gradientZMin = null; this._gradientZMax = null; } static createByConstant(constant) { var gradientVelocity = new GradientVelocity(); gradientVelocity._type = 0; gradientVelocity._constant = constant; return gradientVelocity; } static createByGradient(gradientX, gradientY, gradientZ) { var gradientVelocity = new GradientVelocity(); gradientVelocity._type = 1; gradientVelocity._gradientX = gradientX; gradientVelocity._gradientY = gradientY; gradientVelocity._gradientZ = gradientZ; return gradientVelocity; } static createByRandomTwoConstant(constantMin, constantMax) { var gradientVelocity = new GradientVelocity(); gradientVelocity._type = 2; gradientVelocity._constantMin = constantMin; gradientVelocity._constantMax = constantMax; return gradientVelocity; } static createByRandomTwoGradient(gradientXMin, gradientXMax, gradientYMin, gradientYMax, gradientZMin, gradientZMax) { var gradientVelocity = new GradientVelocity(); gradientVelocity._type = 3; gradientVelocity._gradientXMin = gradientXMin; gradientVelocity._gradientXMax = gradientXMax; gradientVelocity._gradientYMin = gradientYMin; gradientVelocity._gradientYMax = gradientYMax; gradientVelocity._gradientZMin = gradientZMin; gradientVelocity._gradientZMax = gradientZMax; return gradientVelocity; } get type() { return this._type; } get constant() { return this._constant; } get gradientX() { return this._gradientX; } get gradientY() { return this._gradientY; } get gradientZ() { return this._gradientZ; } get constantMin() { return this._constantMin; } get constantMax() { return this._constantMax; } get gradientXMin() { return this._gradientXMin; } get gradientXMax() { return this._gradientXMax; } get gradientYMin() { return this._gradientYMin; } get gradientYMax() { return this._gradientYMax; } get gradientZMin() { return this._gradientZMin; } get gradientZMax() { return this._gradientZMax; } cloneTo(destObject) { var destGradientVelocity = destObject; destGradientVelocity._type = this._type; this._constant.cloneTo(destGradientVelocity._constant); this._gradientX.cloneTo(destGradientVelocity._gradientX); this._gradientY.cloneTo(destGradientVelocity._gradientY); this._gradientZ.cloneTo(destGradientVelocity._gradientZ); this._constantMin.cloneTo(destGradientVelocity._constantMin); this._constantMax.cloneTo(destGradientVelocity._constantMax); this._gradientXMin.cloneTo(destGradientVelocity._gradientXMin); this._gradientXMax.cloneTo(destGradientVelocity._gradientXMax); this._gradientYMin.cloneTo(destGradientVelocity._gradientYMin); this._gradientYMax.cloneTo(destGradientVelocity._gradientYMax); this._gradientZMin.cloneTo(destGradientVelocity._gradientZMin); this._gradientZMax.cloneTo(destGradientVelocity._gradientZMax); } clone() { var destGradientVelocity = new GradientVelocity(); this.cloneTo(destGradientVelocity); return destGradientVelocity; } } class RotationOverLifetime { constructor(angularVelocity) { this._angularVelocity = angularVelocity; } get angularVelocity() { return this._angularVelocity; } cloneTo(destObject) { var destRotationOverLifetime = destObject; this._angularVelocity.cloneTo(destRotationOverLifetime._angularVelocity); destRotationOverLifetime.enable = this.enable; } clone() { var destAngularVelocity; switch (this._angularVelocity.type) { case 0: if (this._angularVelocity.separateAxes) destAngularVelocity = GradientAngularVelocity.createByConstantSeparate(this._angularVelocity.constantSeparate.clone()); else destAngularVelocity = GradientAngularVelocity.createByConstant(this._angularVelocity.constant); break; case 1: if (this._angularVelocity.separateAxes) destAngularVelocity = GradientAngularVelocity.createByGradientSeparate(this._angularVelocity.gradientX.clone(), this._angularVelocity.gradientY.clone(), this._angularVelocity.gradientZ.clone()); else destAngularVelocity = GradientAngularVelocity.createByGradient(this._angularVelocity.gradient.clone()); break; case 2: if (this._angularVelocity.separateAxes) destAngularVelocity = GradientAngularVelocity.createByRandomTwoConstantSeparate(this._angularVelocity.constantMinSeparate.clone(), this._angularVelocity.constantMaxSeparate.clone()); else destAngularVelocity = GradientAngularVelocity.createByRandomTwoConstant(this._angularVelocity.constantMin, this._angularVelocity.constantMax); break; case 3: if (this._angularVelocity.separateAxes) destAngularVelocity = GradientAngularVelocity.createByRandomTwoGradientSeparate(this._angularVelocity.gradientXMin.clone(), this._angularVelocity.gradientYMin.clone(), this._angularVelocity.gradientZMin.clone(), this._angularVelocity.gradientWMin.clone(), this._angularVelocity.gradientXMax.clone(), this._angularVelocity.gradientYMax.clone(), this._angularVelocity.gradientZMax.clone(), this._angularVelocity.gradientWMax.clone()); else destAngularVelocity = GradientAngularVelocity.createByRandomTwoGradient(this._angularVelocity.gradientMin.clone(), this._angularVelocity.gradientMax.clone()); break; } var destRotationOverLifetime = new RotationOverLifetime(destAngularVelocity); destRotationOverLifetime.enable = this.enable; return destRotationOverLifetime; } } class BaseShape { constructor() { this.enable = true; this.randomDirection = 0; } _getShapeBoundBox(boundBox) { throw new Error("BaseShape: must override it."); } _getSpeedBoundBox(boundBox) { throw new Error("BaseShape: must override it."); } generatePositionAndDirection(position, direction, rand = null, randomSeeds = null) { throw new Error("BaseShape: must override it."); } _calculateProceduralBounds(boundBox, emitterPosScale, minMaxBounds) { this._getShapeBoundBox(boundBox); var min = boundBox.min; var max = boundBox.max; Vector3.multiply(min, emitterPosScale, min); Vector3.multiply(max, emitterPosScale, max); var speedBounds = new BoundBox(new Vector3(), new Vector3()); if (this.randomDirection) { speedBounds.min = new Vector3(-1, -1, -1); speedBounds.max = new Vector3(1, 1, 1); } else { this._getSpeedBoundBox(speedBounds); } var maxSpeedBound = new BoundBox(new Vector3(), new Vector3()); var maxSpeedMin = maxSpeedBound.min; var maxSpeedMax = maxSpeedBound.max; Vector3.scale(speedBounds.min, minMaxBounds.y, maxSpeedMin); Vector3.scale(speedBounds.max, minMaxBounds.y, maxSpeedMax); Vector3.add(boundBox.min, maxSpeedMin, maxSpeedMin); Vector3.add(boundBox.max, maxSpeedMax, maxSpeedMax); Vector3.min(boundBox.min, maxSpeedMin, boundBox.min); Vector3.max(boundBox.max, maxSpeedMin, boundBox.max); var minSpeedBound = new BoundBox(new Vector3(), new Vector3()); var minSpeedMin = minSpeedBound.min; var minSpeedMax = minSpeedBound.max; Vector3.scale(speedBounds.min, minMaxBounds.x, minSpeedMin); Vector3.scale(speedBounds.max, minMaxBounds.x, minSpeedMax); Vector3.min(minSpeedBound.min, minSpeedMax, maxSpeedMin); Vector3.max(minSpeedBound.min, minSpeedMax, maxSpeedMax); Vector3.min(boundBox.min, maxSpeedMin, boundBox.min); Vector3.max(boundBox.max, maxSpeedMin, boundBox.max); } cloneTo(destObject) { var destShape = destObject; destShape.enable = this.enable; } clone() { var destShape = new BaseShape(); this.cloneTo(destShape); return destShape; } } class ShapeUtils { static _randomPointUnitArcCircle(arc, out, rand = null) { var angle; if (rand) angle = rand.getFloat() * arc; else angle = Math.random() * arc; out.x = Math.cos(angle); out.y = Math.sin(angle); } static _randomPointInsideUnitArcCircle(arc, out, rand = null) { ShapeUtils._randomPointUnitArcCircle(arc, out, rand); var range; if (rand) range = Math.pow(rand.getFloat(), 1.0 / 2.0); else range = Math.pow(Math.random(), 1.0 / 2.0); out.x = out.x * range; out.y = out.y * range; } static _randomPointUnitCircle(out, rand = null) { var angle; if (rand) angle = rand.getFloat() * Math.PI * 2; else angle = Math.random() * Math.PI * 2; out.x = Math.cos(angle); out.y = Math.sin(angle); } static _randomPointInsideUnitCircle(out, rand = null) { ShapeUtils._randomPointUnitCircle(out); var range; if (rand) range = Math.pow(rand.getFloat(), 1.0 / 2.0); else range = Math.pow(Math.random(), 1.0 / 2.0); out.x = out.x * range; out.y = out.y * range; } static _randomPointUnitSphere(out, rand = null) { var z; var a; if (rand) { z = out.z = rand.getFloat() * 2 - 1.0; a = rand.getFloat() * Math.PI * 2; } else { z = out.z = Math.random() * 2 - 1.0; a = Math.random() * Math.PI * 2; } var r = Math.sqrt(1.0 - z * z); out.x = r * Math.cos(a); out.y = r * Math.sin(a); } static _randomPointInsideUnitSphere(out, rand = null) { ShapeUtils._randomPointUnitSphere(out); var range; if (rand) range = Math.pow(rand.getFloat(), 1.0 / 3.0); else range = Math.pow(Math.random(), 1.0 / 3.0); out.x = out.x * range; out.y = out.y * range; out.z = out.z * range; } static _randomPointInsideHalfUnitBox(out, rand = null) { if (rand) { out.x = (rand.getFloat() - 0.5); out.y = (rand.getFloat() - 0.5); out.z = (rand.getFloat() - 0.5); } else { out.x = (Math.random() - 0.5); out.y = (Math.random() - 0.5); out.z = (Math.random() - 0.5); } } constructor() { } } class BoxShape extends BaseShape { constructor() { super(); this.x = 1.0; this.y = 1.0; this.z = 1.0; } _getShapeBoundBox(boundBox) { var min = boundBox.min; min.x = -this.x * 0.5; min.y = -this.y * 0.5; min.z = -this.z * 0.5; var max = boundBox.max; max.x = this.x * 0.5; max.y = this.y * 0.5; max.z = this.z * 0.5; } _getSpeedBoundBox(boundBox) { var min = boundBox.min; min.x = 0.0; min.y = 0.0; min.z = 0.0; var max = boundBox.max; max.x = 0.0; max.y = 1.0; max.z = 0.0; } generatePositionAndDirection(position, direction, rand = null, randomSeeds = null) { if (rand) { rand.seed = randomSeeds[16]; ShapeUtils._randomPointInsideHalfUnitBox(position, rand); randomSeeds[16] = rand.seed; } else { ShapeUtils._randomPointInsideHalfUnitBox(position); } position.x = this.x * position.x; position.y = this.y * position.y; position.z = this.z * position.z; if (this.randomDirection) { if (rand) { rand.seed = randomSeeds[17]; ShapeUtils._randomPointUnitSphere(direction, rand); randomSeeds[17] = rand.seed; } else { ShapeUtils._randomPointUnitSphere(direction); } } else { direction.x = 0.0; direction.y = 0.0; direction.z = 1.0; } } cloneTo(destObject) { super.cloneTo(destObject); var destShape = destObject; destShape.x = this.x; destShape.y = this.y; destShape.z = this.z; destShape.randomDirection = this.randomDirection; } clone() { var destShape = new BoxShape(); this.cloneTo(destShape); return destShape; } } class CircleShape extends BaseShape { constructor() { super(); this.radius = 1.0; this.arc = 360.0 / 180.0 * Math.PI; this.emitFromEdge = false; } _getShapeBoundBox(boundBox) { var min = boundBox.min; min.x = min.z = -this.radius; min.y = 0; var max = boundBox.max; max.x = max.z = this.radius; max.y = 0; } _getSpeedBoundBox(boundBox) { var min = boundBox.min; min.x = min.y = -1; min.z = 0; var max = boundBox.max; max.x = max.y = 1; max.z = 0; } generatePositionAndDirection(position, direction, rand = null, randomSeeds = null) { var positionPoint = CircleShape._tempPositionPoint; if (rand) { rand.seed = randomSeeds[16]; if (this.emitFromEdge) ShapeUtils._randomPointUnitArcCircle(this.arc, CircleShape._tempPositionPoint, rand); else ShapeUtils._randomPointInsideUnitArcCircle(this.arc, CircleShape._tempPositionPoint, rand); randomSeeds[16] = rand.seed; } else { if (this.emitFromEdge) ShapeUtils._randomPointUnitArcCircle(this.arc, CircleShape._tempPositionPoint); else ShapeUtils._randomPointInsideUnitArcCircle(this.arc, CircleShape._tempPositionPoint); } position.x = -positionPoint.x; position.y = positionPoint.y; position.z = 0; Vector3.scale(position, this.radius, position); if (this.randomDirection) { if (rand) { rand.seed = randomSeeds[17]; ShapeUtils._randomPointUnitSphere(direction, rand); randomSeeds[17] = rand.seed; } else { ShapeUtils._randomPointUnitSphere(direction); } } else { position.cloneTo(direction); } } cloneTo(destObject) { super.cloneTo(destObject); var destShape = destObject; destShape.radius = this.radius; destShape.arc = this.arc; destShape.emitFromEdge = this.emitFromEdge; destShape.randomDirection = this.randomDirection; } clone() { var destShape = new CircleShape(); this.cloneTo(destShape); return destShape; } } CircleShape._tempPositionPoint = new Vector2(); class ConeShape extends BaseShape { constructor() { super(); this.angle = 25.0 / 180.0 * Math.PI; this.radius = 1.0; this.length = 5.0; this.emitType = 0; } _getShapeBoundBox(boundBox) { const coneRadius2 = this.radius + this.length * Math.sin(this.angle); const coneLength = this.length * Math.cos(this.angle); var min = boundBox.min; min.x = min.y = -coneRadius2; min.z = 0; var max = boundBox.max; max.x = max.y = coneRadius2; max.z = coneLength; } _getSpeedBoundBox(boundBox) { const sinA = Math.sin(this.angle); var min = boundBox.min; min.x = min.y = -sinA; min.z = 0; var max = boundBox.max; max.x = max.y = sinA; max.z = 1; } generatePositionAndDirection(position, direction, rand = null, randomSeeds = null) { var positionPointE = ConeShape._tempPositionPoint; var positionX; var positionY; var directionPointE; var dirCosA = Math.cos(this.angle); var dirSinA = Math.sin(this.angle); switch (this.emitType) { case 0: if (rand) { rand.seed = randomSeeds[16]; ShapeUtils._randomPointInsideUnitCircle(ConeShape._tempPositionPoint, rand); randomSeeds[16] = rand.seed; } else { ShapeUtils._randomPointInsideUnitCircle(ConeShape._tempPositionPoint); } positionX = positionPointE.x; positionY = positionPointE.y; position.x = positionX * this.radius; position.y = positionY * this.radius; position.z = 0; if (this.randomDirection) { if (rand) { rand.seed = randomSeeds[17]; ShapeUtils._randomPointInsideUnitCircle(ConeShape._tempDirectionPoint, rand); randomSeeds[17] = rand.seed; } else { ShapeUtils._randomPointInsideUnitCircle(ConeShape._tempDirectionPoint); } directionPointE = ConeShape._tempDirectionPoint; direction.x = directionPointE.x * dirSinA; direction.y = directionPointE.y * dirSinA; } else { direction.x = positionX * dirSinA; direction.y = positionY * dirSinA; } direction.z = dirCosA; break; case 1: if (rand) { rand.seed = randomSeeds[16]; ShapeUtils._randomPointUnitCircle(ConeShape._tempPositionPoint, rand); randomSeeds[16] = rand.seed; } else { ShapeUtils._randomPointUnitCircle(ConeShape._tempPositionPoint); } positionX = positionPointE.x; positionY = positionPointE.y; position.x = positionX * this.radius; position.y = positionY * this.radius; position.z = 0; if (this.randomDirection) { if (rand) { rand.seed = randomSeeds[17]; ShapeUtils._randomPointInsideUnitCircle(ConeShape._tempDirectionPoint, rand); randomSeeds[17] = rand.seed; } else { ShapeUtils._randomPointInsideUnitCircle(ConeShape._tempDirectionPoint); } directionPointE = ConeShape._tempDirectionPoint; direction.x = directionPointE.x * dirSinA; direction.y = directionPointE.y * dirSinA; } else { direction.x = positionX * dirSinA; direction.y = positionY * dirSinA; } direction.z = dirCosA; break; case 2: if (rand) { rand.seed = randomSeeds[16]; ShapeUtils._randomPointInsideUnitCircle(ConeShape._tempPositionPoint, rand); } else { ShapeUtils._randomPointInsideUnitCircle(ConeShape._tempPositionPoint); } positionX = positionPointE.x; positionY = positionPointE.y; position.x = positionX * this.radius; position.y = positionY * this.radius; position.z = 0; direction.x = positionX * dirSinA; direction.y = positionY * dirSinA; direction.z = dirCosA; Vector3.normalize(direction, direction); if (rand) { Vector3.scale(direction, this.length * rand.getFloat(), direction); randomSeeds[16] = rand.seed; } else { Vector3.scale(direction, this.length * Math.random(), direction); } Vector3.add(position, direction, position); if (this.randomDirection) { if (rand) { rand.seed = randomSeeds[17]; ShapeUtils._randomPointUnitSphere(direction, rand); randomSeeds[17] = rand.seed; } else { ShapeUtils._randomPointUnitSphere(direction); } } break; case 3: if (rand) { rand.seed = randomSeeds[16]; ShapeUtils._randomPointUnitCircle(ConeShape._tempPositionPoint, rand); } else { ShapeUtils._randomPointUnitCircle(ConeShape._tempPositionPoint); } positionX = positionPointE.x; positionY = positionPointE.y; position.x = positionX * this.radius; position.y = positionY * this.radius; position.z = 0; direction.x = positionX * dirSinA; direction.y = positionY * dirSinA; direction.z = dirCosA; Vector3.normalize(direction, direction); if (rand) { Vector3.scale(direction, this.length * rand.getFloat(), direction); randomSeeds[16] = rand.seed; } else { Vector3.scale(direction, this.length * Math.random(), direction); } Vector3.add(position, direction, position); if (this.randomDirection) { if (rand) { rand.seed = randomSeeds[17]; ShapeUtils._randomPointUnitSphere(direction, rand); randomSeeds[17] = rand.seed; } else { ShapeUtils._randomPointUnitSphere(direction); } } break; default: throw new Error("ConeShape:emitType is invalid."); } } cloneTo(destObject) { super.cloneTo(destObject); var destShape = destObject; destShape.angle = this.angle; destShape.radius = this.radius; destShape.length = this.length; destShape.emitType = this.emitType; destShape.randomDirection = this.randomDirection; } clone() { var destShape = new ConeShape(); this.cloneTo(destShape); return destShape; } } ConeShape._tempPositionPoint = new Vector2(); ConeShape._tempDirectionPoint = new Vector2(); class HemisphereShape extends BaseShape { constructor() { super(); this.radius = 1.0; this.emitFromShell = false; } _getShapeBoundBox(boundBox) { var min = boundBox.min; min.x = min.y = min.z = -this.radius; var max = boundBox.max; max.x = max.y = this.radius; max.z = 0; } _getSpeedBoundBox(boundBox) { var min = boundBox.min; min.x = min.y = -1; min.z = 0; var max = boundBox.max; max.x = max.y = max.z = 1; } generatePositionAndDirection(position, direction, rand = null, randomSeeds = null) { if (rand) { rand.seed = randomSeeds[16]; if (this.emitFromShell) ShapeUtils._randomPointUnitSphere(position, rand); else ShapeUtils._randomPointInsideUnitSphere(position, rand); randomSeeds[16] = rand.seed; } else { if (this.emitFromShell) ShapeUtils._randomPointUnitSphere(position); else ShapeUtils._randomPointInsideUnitSphere(position); } Vector3.scale(position, this.radius, position); var z = position.z; (z < 0.0) && (position.z = z * -1.0); if (this.randomDirection) { if (rand) { rand.seed = randomSeeds[17]; ShapeUtils._randomPointUnitSphere(direction, rand); randomSeeds[17] = rand.seed; } else { ShapeUtils._randomPointUnitSphere(direction); } } else { position.cloneTo(direction); } } cloneTo(destObject) { super.cloneTo(destObject); var destShape = destObject; destShape.radius = this.radius; destShape.emitFromShell = this.emitFromShell; destShape.randomDirection = this.randomDirection; } clone() { var destShape = new HemisphereShape(); this.cloneTo(destShape); return destShape; } } class SphereShape extends BaseShape { constructor() { super(); this.radius = 1.0; this.emitFromShell = false; } _getShapeBoundBox(boundBox) { var min = boundBox.min; min.x = min.y = min.z = -this.radius; var max = boundBox.max; max.x = max.y = max.z = this.radius; } _getSpeedBoundBox(boundBox) { var min = boundBox.min; min.x = min.y = min.z = -1; var max = boundBox.max; max.x = max.y = max.z = 1; } generatePositionAndDirection(position, direction, rand = null, randomSeeds = null) { if (rand) { rand.seed = randomSeeds[16]; if (this.emitFromShell) ShapeUtils._randomPointUnitSphere(position, rand); else ShapeUtils._randomPointInsideUnitSphere(position, rand); randomSeeds[16] = rand.seed; } else { if (this.emitFromShell) ShapeUtils._randomPointUnitSphere(position); else ShapeUtils._randomPointInsideUnitSphere(position); } Vector3.scale(position, this.radius, position); if (this.randomDirection) { if (rand) { rand.seed = randomSeeds[17]; ShapeUtils._randomPointUnitSphere(direction, rand); randomSeeds[17] = rand.seed; } else { ShapeUtils._randomPointUnitSphere(direction); } } else { position.cloneTo(direction); } } cloneTo(destObject) { super.cloneTo(destObject); var destShape = destObject; destShape.radius = this.radius; destShape.emitFromShell = this.emitFromShell; destShape.randomDirection = this.randomDirection; } clone() { var destShape = new SphereShape(); this.cloneTo(destShape); return destShape; } } class SizeOverLifetime { constructor(size) { this._size = size; } get size() { return this._size; } cloneTo(destObject) { var destSizeOverLifetime = destObject; this._size.cloneTo(destSizeOverLifetime._size); destSizeOverLifetime.enable = this.enable; } clone() { var destSize; switch (this._size.type) { case 0: if (this._size.separateAxes) destSize = GradientSize.createByGradientSeparate(this._size.gradientX.clone(), this._size.gradientY.clone(), this._size.gradientZ.clone()); else destSize = GradientSize.createByGradient(this._size.gradient.clone()); break; case 1: if (this._size.separateAxes) destSize = GradientSize.createByRandomTwoConstantSeparate(this._size.constantMinSeparate.clone(), this._size.constantMaxSeparate.clone()); else destSize = GradientSize.createByRandomTwoConstant(this._size.constantMin, this._size.constantMax); break; case 2: if (this._size.separateAxes) destSize = GradientSize.createByRandomTwoGradientSeparate(this._size.gradientXMin.clone(), this._size.gradientYMin.clone(), this._size.gradientZMin.clone(), this._size.gradientXMax.clone(), this._size.gradientYMax.clone(), this._size.gradientZMax.clone()); else destSize = GradientSize.createByRandomTwoGradient(this._size.gradientMin.clone(), this._size.gradientMax.clone()); break; } var destSizeOverLifetime = new SizeOverLifetime(destSize); destSizeOverLifetime.enable = this.enable; return destSizeOverLifetime; } } class StartFrame { constructor() { this._type = 0; this._constant = 0; this._constantMin = 0; this._constantMax = 0; } static createByConstant(constant = 0) { var rotationOverLifetime = new StartFrame(); rotationOverLifetime._type = 0; rotationOverLifetime._constant = constant; return rotationOverLifetime; } static createByRandomTwoConstant(constantMin = 0, constantMax = 0) { var rotationOverLifetime = new StartFrame(); rotationOverLifetime._type = 1; rotationOverLifetime._constantMin = constantMin; rotationOverLifetime._constantMax = constantMax; return rotationOverLifetime; } get type() { return this._type; } get constant() { return this._constant; } get constantMin() { return this._constantMin; } get constantMax() { return this._constantMax; } cloneTo(destObject) { var destStartFrame = destObject; destStartFrame._type = this._type; destStartFrame._constant = this._constant; destStartFrame._constantMin = this._constantMin; destStartFrame._constantMax = this._constantMax; } clone() { var destStartFrame = new StartFrame(); this.cloneTo(destStartFrame); return destStartFrame; } } class TextureSheetAnimation { constructor(frame, startFrame) { this.type = 0; this.randomRow = false; this.rowIndex = 0; this.cycles = 0; this.enableUVChannels = 0; this.enable = false; this.tiles = new Vector2(1, 1); this.type = 0; this.randomRow = true; this.rowIndex = 0; this.cycles = 1; this.enableUVChannels = 1; this._frame = frame; this._startFrame = startFrame; } get frame() { return this._frame; } get startFrame() { return this._startFrame; } cloneTo(destObject) { var destTextureSheetAnimation = destObject; this.tiles.cloneTo(destTextureSheetAnimation.tiles); destTextureSheetAnimation.type = this.type; destTextureSheetAnimation.randomRow = this.randomRow; destTextureSheetAnimation.rowIndex = this.rowIndex; destTextureSheetAnimation.cycles = this.cycles; destTextureSheetAnimation.enableUVChannels = this.enableUVChannels; destTextureSheetAnimation.enable = this.enable; this._frame.cloneTo(destTextureSheetAnimation._frame); this._startFrame.cloneTo(destTextureSheetAnimation._startFrame); } clone() { var destFrame; switch (this._frame.type) { case 0: destFrame = FrameOverTime.createByConstant(this._frame.constant); break; case 1: destFrame = FrameOverTime.createByOverTime(this._frame.frameOverTimeData.clone()); break; case 2: destFrame = FrameOverTime.createByRandomTwoConstant(this._frame.constantMin, this._frame.constantMax); break; case 3: destFrame = FrameOverTime.createByRandomTwoOverTime(this._frame.frameOverTimeDataMin.clone(), this._frame.frameOverTimeDataMax.clone()); break; } var destStartFrame; switch (this._startFrame.type) { case 0: destStartFrame = StartFrame.createByConstant(this._startFrame.constant); break; case 1: destStartFrame = StartFrame.createByRandomTwoConstant(this._startFrame.constantMin, this._startFrame.constantMax); break; } var destTextureSheetAnimation = new TextureSheetAnimation(destFrame, destStartFrame); this.cloneTo(destTextureSheetAnimation); return destTextureSheetAnimation; } } class VelocityOverLifetime { constructor(velocity) { this.enable = false; this.space = 0; this._velocity = velocity; } get velocity() { return this._velocity; } cloneTo(destObject) { var destVelocityOverLifetime = destObject; this._velocity.cloneTo(destVelocityOverLifetime._velocity); destVelocityOverLifetime.enable = this.enable; destVelocityOverLifetime.space = this.space; } clone() { var destVelocity; switch (this._velocity.type) { case 0: destVelocity = GradientVelocity.createByConstant(this._velocity.constant.clone()); break; case 1: destVelocity = GradientVelocity.createByGradient(this._velocity.gradientX.clone(), this._velocity.gradientY.clone(), this._velocity.gradientZ.clone()); break; case 2: destVelocity = GradientVelocity.createByRandomTwoConstant(this._velocity.constantMin.clone(), this._velocity.constantMax.clone()); break; case 3: destVelocity = GradientVelocity.createByRandomTwoGradient(this._velocity.gradientXMin.clone(), this._velocity.gradientYMin.clone(), this._velocity.gradientZMin.clone(), this._velocity.gradientXMax.clone(), this._velocity.gradientYMax.clone(), this._velocity.gradientZMax.clone()); break; } var destVelocityOverLifetime = new VelocityOverLifetime(destVelocity); destVelocityOverLifetime.enable = this.enable; destVelocityOverLifetime.space = this.space; return destVelocityOverLifetime; } } class ShuriKenParticle3DShaderDeclaration { } ShuriKenParticle3DShaderDeclaration.WORLDPOSITION = Shader3D.propertyNameToID("u_WorldPosition"); ShuriKenParticle3DShaderDeclaration.WORLDROTATION = Shader3D.propertyNameToID("u_WorldRotation"); ShuriKenParticle3DShaderDeclaration.POSITIONSCALE = Shader3D.propertyNameToID("u_PositionScale"); ShuriKenParticle3DShaderDeclaration.SIZESCALE = Shader3D.propertyNameToID("u_SizeScale"); ShuriKenParticle3DShaderDeclaration.SCALINGMODE = Shader3D.propertyNameToID("u_ScalingMode"); ShuriKenParticle3DShaderDeclaration.GRAVITY = Shader3D.propertyNameToID("u_Gravity"); ShuriKenParticle3DShaderDeclaration.THREEDSTARTROTATION = Shader3D.propertyNameToID("u_ThreeDStartRotation"); ShuriKenParticle3DShaderDeclaration.STRETCHEDBILLBOARDLENGTHSCALE = Shader3D.propertyNameToID("u_StretchedBillboardLengthScale"); ShuriKenParticle3DShaderDeclaration.STRETCHEDBILLBOARDSPEEDSCALE = Shader3D.propertyNameToID("u_StretchedBillboardSpeedScale"); ShuriKenParticle3DShaderDeclaration.SIMULATIONSPACE = Shader3D.propertyNameToID("u_SimulationSpace"); ShuriKenParticle3DShaderDeclaration.CURRENTTIME = Shader3D.propertyNameToID("u_CurrentTime"); ShuriKenParticle3DShaderDeclaration.VOLVELOCITYCONST = Shader3D.propertyNameToID("u_VOLVelocityConst"); ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTX = Shader3D.propertyNameToID("u_VOLVelocityGradientX"); ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTY = Shader3D.propertyNameToID("u_VOLVelocityGradientY"); ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTZ = Shader3D.propertyNameToID("u_VOLVelocityGradientZ"); ShuriKenParticle3DShaderDeclaration.VOLVELOCITYCONSTMAX = Shader3D.propertyNameToID("u_VOLVelocityConstMax"); ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTXMAX = Shader3D.propertyNameToID("u_VOLVelocityGradientMaxX"); ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTYMAX = Shader3D.propertyNameToID("u_VOLVelocityGradientMaxY"); ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTZMAX = Shader3D.propertyNameToID("u_VOLVelocityGradientMaxZ"); ShuriKenParticle3DShaderDeclaration.VOLSPACETYPE = Shader3D.propertyNameToID("u_VOLSpaceType"); ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTALPHAS = Shader3D.propertyNameToID("u_ColorOverLifeGradientAlphas"); ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTCOLORS = Shader3D.propertyNameToID("u_ColorOverLifeGradientColors"); ShuriKenParticle3DShaderDeclaration.MAXCOLOROVERLIFEGRADIENTALPHAS = Shader3D.propertyNameToID("u_MaxColorOverLifeGradientAlphas"); ShuriKenParticle3DShaderDeclaration.MAXCOLOROVERLIFEGRADIENTCOLORS = Shader3D.propertyNameToID("u_MaxColorOverLifeGradientColors"); ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENT = Shader3D.propertyNameToID("u_SOLSizeGradient"); ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTX = Shader3D.propertyNameToID("u_SOLSizeGradientX"); ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTY = Shader3D.propertyNameToID("u_SOLSizeGradientY"); ShuriKenParticle3DShaderDeclaration.SOLSizeGradientZ = Shader3D.propertyNameToID("u_SOLSizeGradientZ"); ShuriKenParticle3DShaderDeclaration.SOLSizeGradientMax = Shader3D.propertyNameToID("u_SOLSizeGradientMax"); ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTXMAX = Shader3D.propertyNameToID("u_SOLSizeGradientMaxX"); ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTYMAX = Shader3D.propertyNameToID("u_SOLSizeGradientMaxY"); ShuriKenParticle3DShaderDeclaration.SOLSizeGradientZMAX = Shader3D.propertyNameToID("u_SOLSizeGradientMaxZ"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONST = Shader3D.propertyNameToID("u_ROLAngularVelocityConst"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONSTSEPRARATE = Shader3D.propertyNameToID("u_ROLAngularVelocityConstSeprarate"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENT = Shader3D.propertyNameToID("u_ROLAngularVelocityGradient"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTX = Shader3D.propertyNameToID("u_ROLAngularVelocityGradientX"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTY = Shader3D.propertyNameToID("u_ROLAngularVelocityGradientY"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTZ = Shader3D.propertyNameToID("u_ROLAngularVelocityGradientZ"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONSTMAX = Shader3D.propertyNameToID("u_ROLAngularVelocityConstMax"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONSTMAXSEPRARATE = Shader3D.propertyNameToID("u_ROLAngularVelocityConstMaxSeprarate"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTMAX = Shader3D.propertyNameToID("u_ROLAngularVelocityGradientMax"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTXMAX = Shader3D.propertyNameToID("u_ROLAngularVelocityGradientMaxX"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTYMAX = Shader3D.propertyNameToID("u_ROLAngularVelocityGradientMaxY"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTZMAX = Shader3D.propertyNameToID("u_ROLAngularVelocityGradientMaxZ"); ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTWMAX = Shader3D.propertyNameToID("u_ROLAngularVelocityGradientMaxW"); ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONCYCLES = Shader3D.propertyNameToID("u_TSACycles"); ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONSUBUVLENGTH = Shader3D.propertyNameToID("u_TSASubUVLength"); ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONGRADIENTUVS = Shader3D.propertyNameToID("u_TSAGradientUVs"); ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONGRADIENTMAXUVS = Shader3D.propertyNameToID("u_TSAMaxGradientUVs"); class ShurikenParticleMaterial extends Material { constructor() { super(); this.setShaderName("PARTICLESHURIKEN"); this._color = new Vector4(1.0, 1.0, 1.0, 1.0); this.renderMode = ShurikenParticleMaterial.RENDERMODE_ALPHABLENDED; } static __initDefine__() { ShurikenParticleMaterial.SHADERDEFINE_DIFFUSEMAP = Shader3D.getDefineByName("DIFFUSEMAP"); ShurikenParticleMaterial.SHADERDEFINE_TINTCOLOR = Shader3D.getDefineByName("TINTCOLOR"); ShurikenParticleMaterial.SHADERDEFINE_ADDTIVEFOG = Shader3D.getDefineByName("ADDTIVEFOG"); ShurikenParticleMaterial.SHADERDEFINE_TILINGOFFSET = Shader3D.getDefineByName("TILINGOFFSET"); } get _TintColorR() { return this._color.x; } set _TintColorR(value) { this._color.x = value; this.color = this._color; } get _TintColorG() { return this._color.y; } set _TintColorG(value) { this._color.y = value; this.color = this._color; } get _TintColorB() { return this._color.z; } set _TintColorB(value) { this._color.z = value; this.color = this._color; } get _TintColorA() { return this._color.w; } set _TintColorA(value) { this._color.w = value; this.color = this._color; } get _MainTex_STX() { return this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET).x; } set _MainTex_STX(x) { var tilOff = this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET); tilOff.x = x; this.tilingOffset = tilOff; } get _MainTex_STY() { return this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET).y; } set _MainTex_STY(y) { var tilOff = this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET); tilOff.y = y; this.tilingOffset = tilOff; } get _MainTex_STZ() { return this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET).z; } set _MainTex_STZ(z) { var tilOff = this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET); tilOff.z = z; this.tilingOffset = tilOff; } get _MainTex_STW() { return this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET).w; } set _MainTex_STW(w) { var tilOff = this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET); tilOff.w = w; this.tilingOffset = tilOff; } set renderMode(value) { switch (value) { case ShurikenParticleMaterial.RENDERMODE_ADDTIVE: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.depthWrite = false; this.cull = RenderState.CULL_NONE; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE; this.alphaTest = false; this._shaderValues.addDefine(ShurikenParticleMaterial.SHADERDEFINE_ADDTIVEFOG); break; case ShurikenParticleMaterial.RENDERMODE_ALPHABLENDED: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.depthWrite = false; this.cull = RenderState.CULL_NONE; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; this.alphaTest = false; this._shaderValues.removeDefine(ShurikenParticleMaterial.SHADERDEFINE_ADDTIVEFOG); break; default: throw new Error("ShurikenParticleMaterial : renderMode value error."); } } get colorR() { return this._TintColorR; } set colorR(value) { this._TintColorR = value; } get colorG() { return this._TintColorG; } set colorG(value) { this._TintColorG = value; } get colorB() { return this._TintColorB; } set colorB(value) { this._TintColorB = value; } get colorA() { return this._TintColorA; } set colorA(value) { this._TintColorA = value; } get color() { return this._shaderValues.getVector(ShurikenParticleMaterial.TINTCOLOR); } set color(value) { if (value) this._shaderValues.addDefine(ShurikenParticleMaterial.SHADERDEFINE_TINTCOLOR); else this._shaderValues.removeDefine(ShurikenParticleMaterial.SHADERDEFINE_TINTCOLOR); this._shaderValues.setVector(ShurikenParticleMaterial.TINTCOLOR, value); } get tilingOffsetX() { return this._MainTex_STX; } set tilingOffsetX(x) { this._MainTex_STX = x; } get tilingOffsetY() { return this._MainTex_STY; } set tilingOffsetY(y) { this._MainTex_STY = y; } get tilingOffsetZ() { return this._MainTex_STZ; } set tilingOffsetZ(z) { this._MainTex_STZ = z; } get tilingOffsetW() { return this._MainTex_STW; } set tilingOffsetW(w) { this._MainTex_STW = w; } get tilingOffset() { return this._shaderValues.getVector(ShurikenParticleMaterial.TILINGOFFSET); } set tilingOffset(value) { if (value) { if (value.x != 1 || value.y != 1 || value.z != 0 || value.w != 0) this._shaderValues.addDefine(ShurikenParticleMaterial.SHADERDEFINE_TILINGOFFSET); else this._shaderValues.removeDefine(ShurikenParticleMaterial.SHADERDEFINE_TILINGOFFSET); } else { this._shaderValues.removeDefine(ShurikenParticleMaterial.SHADERDEFINE_TILINGOFFSET); } this._shaderValues.setVector(ShurikenParticleMaterial.TILINGOFFSET, value); } get texture() { return this._shaderValues.getTexture(ShurikenParticleMaterial.DIFFUSETEXTURE); } set texture(value) { if (value) this._shaderValues.addDefine(ShurikenParticleMaterial.SHADERDEFINE_DIFFUSEMAP); else this._shaderValues.removeDefine(ShurikenParticleMaterial.SHADERDEFINE_DIFFUSEMAP); this._shaderValues.setTexture(ShurikenParticleMaterial.DIFFUSETEXTURE, value); } get depthWrite() { return this._shaderValues.getBool(ShurikenParticleMaterial.DEPTH_WRITE); } set depthWrite(value) { this._shaderValues.setBool(ShurikenParticleMaterial.DEPTH_WRITE, value); } get cull() { return this._shaderValues.getInt(ShurikenParticleMaterial.CULL); } set cull(value) { this._shaderValues.setInt(ShurikenParticleMaterial.CULL, value); } get blend() { return this._shaderValues.getInt(ShurikenParticleMaterial.BLEND); } set blend(value) { this._shaderValues.setInt(ShurikenParticleMaterial.BLEND, value); } get blendSrc() { return this._shaderValues.getInt(ShurikenParticleMaterial.BLEND_SRC); } set blendSrc(value) { this._shaderValues.setInt(ShurikenParticleMaterial.BLEND_SRC, value); } get blendDst() { return this._shaderValues.getInt(ShurikenParticleMaterial.BLEND_DST); } set blendDst(value) { this._shaderValues.setInt(ShurikenParticleMaterial.BLEND_DST, value); } get depthTest() { return this._shaderValues.getInt(ShurikenParticleMaterial.DEPTH_TEST); } set depthTest(value) { this._shaderValues.setInt(ShurikenParticleMaterial.DEPTH_TEST, value); } clone() { var dest = new ShurikenParticleMaterial(); this.cloneTo(dest); return dest; } } ShurikenParticleMaterial.RENDERMODE_ALPHABLENDED = 0; ShurikenParticleMaterial.RENDERMODE_ADDTIVE = 1; ShurikenParticleMaterial.DIFFUSETEXTURE = Shader3D.propertyNameToID("u_texture"); ShurikenParticleMaterial.TINTCOLOR = Shader3D.propertyNameToID("u_Tintcolor"); ShurikenParticleMaterial.TILINGOFFSET = Shader3D.propertyNameToID("u_TilingOffset"); ShurikenParticleMaterial.CULL = Shader3D.propertyNameToID("s_Cull"); ShurikenParticleMaterial.BLEND = Shader3D.propertyNameToID("s_Blend"); ShurikenParticleMaterial.BLEND_SRC = Shader3D.propertyNameToID("s_BlendSrc"); ShurikenParticleMaterial.BLEND_DST = Shader3D.propertyNameToID("s_BlendDst"); ShurikenParticleMaterial.DEPTH_TEST = Shader3D.propertyNameToID("s_DepthTest"); ShurikenParticleMaterial.DEPTH_WRITE = Shader3D.propertyNameToID("s_DepthWrite"); class ShurikenParticleRenderer extends BaseRender { constructor(owner) { super(owner); this._finalGravity = new Vector3(); this._tempRotationMatrix = new Matrix4x4(); this._mesh = null; this.stretchedBillboardCameraSpeedScale = 0; this.stretchedBillboardSpeedScale = 0; this.stretchedBillboardLengthScale = 2; this._defaultBoundBox = new BoundBox(new Vector3(), new Vector3()); this.renderMode = 0; this._supportOctree = false; } get renderMode() { return this._renderMode; } set renderMode(value) { if (this._renderMode !== value) { var defineDatas = this._shaderValues; switch (this._renderMode) { case 0: defineDatas.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_BILLBOARD); break; case 1: defineDatas.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_STRETCHEDBILLBOARD); break; case 2: defineDatas.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_HORIZONTALBILLBOARD); break; case 3: defineDatas.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_VERTICALBILLBOARD); break; case 4: defineDatas.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_MESH); break; } this._renderMode = value; switch (value) { case 0: defineDatas.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_BILLBOARD); break; case 1: defineDatas.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_STRETCHEDBILLBOARD); break; case 2: defineDatas.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_HORIZONTALBILLBOARD); break; case 3: defineDatas.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_VERTICALBILLBOARD); break; case 4: defineDatas.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_MESH); break; default: throw new Error("ShurikenParticleRender: unknown renderMode Value."); } var parSys = this._owner.particleSystem; (parSys) && (parSys._initBufferDatas()); } } get mesh() { return this._mesh; } set mesh(value) { if (this._mesh !== value) { (this._mesh) && (this._mesh._removeReference()); this._mesh = value; (value) && (value._addReference()); this._owner.particleSystem._initBufferDatas(); } } _calculateBoundingBox() { var min = this._bounds.getMin(); min.x = -Number.MAX_VALUE; min.y = -Number.MAX_VALUE; min.z = -Number.MAX_VALUE; this._bounds.setMin(min); var max = this._bounds.getMax(); max.x = Number.MAX_VALUE; max.y = Number.MAX_VALUE; max.z = Number.MAX_VALUE; this._bounds.setMax(max); if (Laya.Render.supportWebGLPlusCulling) { var min = this._bounds.getMin(); var max = this._bounds.getMax(); var buffer = FrustumCulling._cullingBuffer; buffer[this._cullingBufferIndex + 1] = min.x; buffer[this._cullingBufferIndex + 2] = min.y; buffer[this._cullingBufferIndex + 3] = min.z; buffer[this._cullingBufferIndex + 4] = max.x; buffer[this._cullingBufferIndex + 5] = max.y; buffer[this._cullingBufferIndex + 6] = max.z; } } _needRender(boundFrustum, context) { if (boundFrustum) { if (boundFrustum.intersects(this.bounds._getBoundBox())) { if (this._owner.particleSystem.isAlive) return true; else return false; } else { return false; } } else { return true; } } _renderUpdate(context, transfrom) { var particleSystem = this._owner.particleSystem; var sv = this._shaderValues; var transform = this._owner.transform; switch (particleSystem.simulationSpace) { case 0: break; case 1: sv.setVector3(ShuriKenParticle3DShaderDeclaration.WORLDPOSITION, transform.position); sv.setQuaternion(ShuriKenParticle3DShaderDeclaration.WORLDROTATION, transform.rotation); break; default: throw new Error("ShurikenParticleMaterial: SimulationSpace value is invalid."); } switch (particleSystem.scaleMode) { case 0: var scale = transform.getWorldLossyScale(); sv.setVector3(ShuriKenParticle3DShaderDeclaration.POSITIONSCALE, scale); sv.setVector3(ShuriKenParticle3DShaderDeclaration.SIZESCALE, scale); break; case 1: var localScale = transform.localScale; sv.setVector3(ShuriKenParticle3DShaderDeclaration.POSITIONSCALE, localScale); sv.setVector3(ShuriKenParticle3DShaderDeclaration.SIZESCALE, localScale); break; case 2: sv.setVector3(ShuriKenParticle3DShaderDeclaration.POSITIONSCALE, transform.getWorldLossyScale()); sv.setVector3(ShuriKenParticle3DShaderDeclaration.SIZESCALE, Vector3._ONE); break; } Vector3.scale(Physics3DUtils.gravity, particleSystem.gravityModifier, this._finalGravity); sv.setVector3(ShuriKenParticle3DShaderDeclaration.GRAVITY, this._finalGravity); sv.setInt(ShuriKenParticle3DShaderDeclaration.SIMULATIONSPACE, particleSystem.simulationSpace); sv.setBool(ShuriKenParticle3DShaderDeclaration.THREEDSTARTROTATION, particleSystem.threeDStartRotation); sv.setInt(ShuriKenParticle3DShaderDeclaration.SCALINGMODE, particleSystem.scaleMode); sv.setNumber(ShuriKenParticle3DShaderDeclaration.STRETCHEDBILLBOARDLENGTHSCALE, this.stretchedBillboardLengthScale); sv.setNumber(ShuriKenParticle3DShaderDeclaration.STRETCHEDBILLBOARDSPEEDSCALE, this.stretchedBillboardSpeedScale); sv.setNumber(ShuriKenParticle3DShaderDeclaration.CURRENTTIME, particleSystem._currentTime); } get bounds() { if (this._boundsChange) { this._calculateBoundingBox(); this._boundsChange = false; } return this._bounds; } _destroy() { super._destroy(); (this._mesh) && (this._mesh._removeReference(), this._mesh = null); } } class VertexShuriKenParticle { constructor() { } } VertexShuriKenParticle.PARTICLE_CORNERTEXTURECOORDINATE0 = 5; VertexShuriKenParticle.PARTICLE_POSITION0 = 1; VertexShuriKenParticle.PARTICLE_COLOR0 = 2; VertexShuriKenParticle.PARTICLE_TEXTURECOORDINATE0 = 3; VertexShuriKenParticle.PARTICLE_SHAPEPOSITIONSTARTLIFETIME = 4; VertexShuriKenParticle.PARTICLE_DIRECTIONTIME = 0; VertexShuriKenParticle.PARTICLE_STARTCOLOR0 = 6; VertexShuriKenParticle.PARTICLE_ENDCOLOR0 = 7; VertexShuriKenParticle.PARTICLE_STARTSIZE = 8; VertexShuriKenParticle.PARTICLE_STARTROTATION = 9; VertexShuriKenParticle.PARTICLE_STARTSPEED = 10; VertexShuriKenParticle.PARTICLE_RANDOM0 = 11; VertexShuriKenParticle.PARTICLE_RANDOM1 = 12; VertexShuriKenParticle.PARTICLE_SIMULATIONWORLDPOSTION = 13; VertexShuriKenParticle.PARTICLE_SIMULATIONWORLDROTATION = 14; class VertexShurikenParticleBillboard extends VertexShuriKenParticle { constructor(cornerTextureCoordinate, positionStartLifeTime, velocity, startColor, startSize, startRotation0, startRotation1, startRotation2, ageAddScale, time, startSpeed, randoms0, randoms1, simulationWorldPostion) { super(); this._cornerTextureCoordinate = cornerTextureCoordinate; this._positionStartLifeTime = positionStartLifeTime; this._velocity = velocity; this._startColor = startColor; this._startSize = startSize; this._startRotation0 = startRotation0; this._startRotation1 = startRotation1; this._startRotation2 = startRotation2; this._startLifeTime = ageAddScale; this._time = time; this._startSpeed = startSpeed; this._randoms0 = this.random0; this._randoms1 = this.random1; this._simulationWorldPostion = simulationWorldPostion; } static get vertexDeclaration() { return VertexShurikenParticleBillboard._vertexDeclaration; } static __init__() { VertexShurikenParticleBillboard._vertexDeclaration = new VertexDeclaration(152, [new VertexElement(0, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_CORNERTEXTURECOORDINATE0), new VertexElement(16, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_SHAPEPOSITIONSTARTLIFETIME), new VertexElement(32, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_DIRECTIONTIME), new VertexElement(48, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_STARTCOLOR0), new VertexElement(64, VertexElementFormat.Vector3, VertexShuriKenParticle.PARTICLE_STARTSIZE), new VertexElement(76, VertexElementFormat.Vector3, VertexShuriKenParticle.PARTICLE_STARTROTATION), new VertexElement(88, VertexElementFormat.Single, VertexShuriKenParticle.PARTICLE_STARTSPEED), new VertexElement(92, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_RANDOM0), new VertexElement(108, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_RANDOM1), new VertexElement(124, VertexElementFormat.Vector3, VertexShuriKenParticle.PARTICLE_SIMULATIONWORLDPOSTION), new VertexElement(136, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_SIMULATIONWORLDROTATION)]); } get cornerTextureCoordinate() { return this._cornerTextureCoordinate; } get positionStartLifeTime() { return this._positionStartLifeTime; } get velocity() { return this._velocity; } get startColor() { return this._startColor; } get startSize() { return this._startSize; } get startRotation0() { return this._startRotation0; } get startRotation1() { return this._startRotation1; } get startRotation2() { return this._startRotation2; } get startLifeTime() { return this._startLifeTime; } get time() { return this._time; } get startSpeed() { return this._startSpeed; } get random0() { return this._randoms0; } get random1() { return this._randoms1; } get simulationWorldPostion() { return this._simulationWorldPostion; } } class VertexShurikenParticleMesh extends VertexShuriKenParticle { constructor(cornerTextureCoordinate, positionStartLifeTime, velocity, startColor, startSize, startRotation0, startRotation1, startRotation2, ageAddScale, time, startSpeed, randoms0, randoms1, simulationWorldPostion) { super(); this._cornerTextureCoordinate = cornerTextureCoordinate; this._positionStartLifeTime = positionStartLifeTime; this._velocity = velocity; this._startColor = startColor; this._startSize = startSize; this._startRotation0 = startRotation0; this._startRotation1 = startRotation1; this._startRotation2 = startRotation2; this._startLifeTime = ageAddScale; this._time = time; this._startSpeed = startSpeed; this._randoms0 = this.random0; this._randoms1 = this.random1; this._simulationWorldPostion = simulationWorldPostion; } static __init__() { VertexShurikenParticleMesh._vertexDeclaration = new VertexDeclaration(172, [new VertexElement(0, VertexElementFormat.Vector3, VertexShuriKenParticle.PARTICLE_POSITION0), new VertexElement(12, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_COLOR0), new VertexElement(28, VertexElementFormat.Vector2, VertexShuriKenParticle.PARTICLE_TEXTURECOORDINATE0), new VertexElement(36, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_SHAPEPOSITIONSTARTLIFETIME), new VertexElement(52, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_DIRECTIONTIME), new VertexElement(68, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_STARTCOLOR0), new VertexElement(84, VertexElementFormat.Vector3, VertexShuriKenParticle.PARTICLE_STARTSIZE), new VertexElement(96, VertexElementFormat.Vector3, VertexShuriKenParticle.PARTICLE_STARTROTATION), new VertexElement(108, VertexElementFormat.Single, VertexShuriKenParticle.PARTICLE_STARTSPEED), new VertexElement(112, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_RANDOM0), new VertexElement(128, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_RANDOM1), new VertexElement(144, VertexElementFormat.Vector3, VertexShuriKenParticle.PARTICLE_SIMULATIONWORLDPOSTION), new VertexElement(156, VertexElementFormat.Vector4, VertexShuriKenParticle.PARTICLE_SIMULATIONWORLDROTATION)]); } static get vertexDeclaration() { return VertexShurikenParticleMesh._vertexDeclaration; } get cornerTextureCoordinate() { return this._cornerTextureCoordinate; } get position() { return this._positionStartLifeTime; } get velocity() { return this._velocity; } get startColor() { return this._startColor; } get startSize() { return this._startSize; } get startRotation0() { return this._startRotation0; } get startRotation1() { return this._startRotation1; } get startRotation2() { return this._startRotation2; } get startLifeTime() { return this._startLifeTime; } get time() { return this._time; } get startSpeed() { return this._startSpeed; } get random0() { return this._randoms0; } get random1() { return this._randoms1; } get simulationWorldPostion() { return this._simulationWorldPostion; } } class Rand { constructor(seed) { this._temp = new Uint32Array(1); this.seeds = new Uint32Array(4); this.seeds[0] = seed; this.seeds[1] = this.seeds[0] * 0x6C078965 + 1; this.seeds[2] = this.seeds[1] * 0x6C078965 + 1; this.seeds[3] = this.seeds[2] * 0x6C078965 + 1; } static getFloatFromInt(v) { return (v & 0x007FFFFF) * (1.0 / 8388607.0); } static getByteFromInt(v) { return (v & 0x007FFFFF) >>> 15; } get seed() { return this.seeds[0]; } set seed(seed) { this.seeds[0] = seed; this.seeds[1] = this.seeds[0] * 0x6C078965 + 1; this.seeds[2] = this.seeds[1] * 0x6C078965 + 1; this.seeds[3] = this.seeds[2] * 0x6C078965 + 1; } getUint() { this._temp[0] = this.seeds[0] ^ (this.seeds[0] << 11); this.seeds[0] = this.seeds[1]; this.seeds[1] = this.seeds[2]; this.seeds[2] = this.seeds[3]; this.seeds[3] = (this.seeds[3] ^ (this.seeds[3] >>> 19)) ^ (this._temp[0] ^ (this._temp[0] >>> 8)); return this.seeds[3]; } getFloat() { this.getUint(); return (this.seeds[3] & 0x007FFFFF) * (1.0 / 8388607.0); } getSignedFloat() { return this.getFloat() * 2.0 - 1.0; } } class Emission { constructor() { this._emissionRate = 10; this._destroyed = false; this._bursts = []; } set emissionRate(value) { if (value < 0) throw new Error("ParticleBaseShape:emissionRate value must large or equal than 0."); this._emissionRate = value; } get emissionRate() { return this._emissionRate; } get destroyed() { return this._destroyed; } destroy() { this._bursts = null; this._destroyed = true; } getBurstsCount() { return this._bursts.length; } getBurstByIndex(index) { return this._bursts[index]; } addBurst(burst) { var burstsCount = this._bursts.length; if (burstsCount > 0) for (var i = 0; i < burstsCount; i++) { if (this._bursts[i].time > burst.time) this._bursts.splice(i, 0, burst); } this._bursts.push(burst); } removeBurst(burst) { var index = this._bursts.indexOf(burst); if (index !== -1) { this._bursts.splice(index, 1); } } removeBurstByIndex(index) { this._bursts.splice(index, 1); } clearBurst() { this._bursts.length = 0; } cloneTo(destObject) { var destEmission = destObject; var destBursts = destEmission._bursts; destBursts.length = this._bursts.length; for (var i = 0, n = this._bursts.length; i < n; i++) { var destBurst = destBursts[i]; if (destBurst) this._bursts[i].cloneTo(destBurst); else destBursts[i] = this._bursts[i].clone(); } destEmission._emissionRate = this._emissionRate; destEmission.enable = this.enable; } clone() { var destEmission = new Emission(); this.cloneTo(destEmission); return destEmission; } } class ShurikenParticleData { constructor() { } static _getStartLifetimeFromGradient(startLifeTimeGradient, emissionTime) { for (var i = 1, n = startLifeTimeGradient.gradientCount; i < n; i++) { var key = startLifeTimeGradient.getKeyByIndex(i); if (key >= emissionTime) { var lastKey = startLifeTimeGradient.getKeyByIndex(i - 1); var age = (emissionTime - lastKey) / (key - lastKey); return Laya.MathUtil.lerp(startLifeTimeGradient.getValueByIndex(i - 1), startLifeTimeGradient.getValueByIndex(i), age); } } throw new Error("ShurikenParticleData: can't get value foam startLifeTimeGradient."); } static _randomInvertRoationArray(rotatonE, outE, randomizeRotationDirection, rand, randomSeeds) { var randDic; if (rand) { rand.seed = randomSeeds[6]; randDic = rand.getFloat(); randomSeeds[6] = rand.seed; } else { randDic = Math.random(); } if (randDic < randomizeRotationDirection) { outE.x = -rotatonE.x; outE.y = -rotatonE.y; outE.z = -rotatonE.z; } else { outE.x = rotatonE.x; outE.y = rotatonE.y; outE.z = rotatonE.z; } } static _randomInvertRoation(rotaton, randomizeRotationDirection, rand, randomSeeds) { var randDic; if (rand) { rand.seed = randomSeeds[6]; randDic = rand.getFloat(); randomSeeds[6] = rand.seed; } else { randDic = Math.random(); } if (randDic < randomizeRotationDirection) rotaton = -rotaton; return rotaton; } static create(particleSystem, particleRender, transform) { var autoRandomSeed = particleSystem.autoRandomSeed; var rand = particleSystem._rand; var randomSeeds = particleSystem._randomSeeds; switch (particleSystem.startColorType) { case 0: var constantStartColor = particleSystem.startColorConstant; ShurikenParticleData.startColor.x = constantStartColor.x; ShurikenParticleData.startColor.y = constantStartColor.y; ShurikenParticleData.startColor.z = constantStartColor.z; ShurikenParticleData.startColor.w = constantStartColor.w; break; case 2: if (autoRandomSeed) { Vector4.lerp(particleSystem.startColorConstantMin, particleSystem.startColorConstantMax, Math.random(), ShurikenParticleData.startColor); } else { rand.seed = randomSeeds[3]; Vector4.lerp(particleSystem.startColorConstantMin, particleSystem.startColorConstantMax, rand.getFloat(), ShurikenParticleData.startColor); randomSeeds[3] = rand.seed; } break; } var colorOverLifetime = particleSystem.colorOverLifetime; if (colorOverLifetime && colorOverLifetime.enable) { var color = colorOverLifetime.color; switch (color.type) { case 0: ShurikenParticleData.startColor.x = ShurikenParticleData.startColor.x * color.constant.x; ShurikenParticleData.startColor.y = ShurikenParticleData.startColor.y * color.constant.y; ShurikenParticleData.startColor.z = ShurikenParticleData.startColor.z * color.constant.z; ShurikenParticleData.startColor.w = ShurikenParticleData.startColor.w * color.constant.w; break; case 2: var colorRandom; if (autoRandomSeed) { colorRandom = Math.random(); } else { rand.seed = randomSeeds[10]; colorRandom = rand.getFloat(); randomSeeds[10] = rand.seed; } var minConstantColor = color.constantMin; var maxConstantColor = color.constantMax; ShurikenParticleData.startColor.x = ShurikenParticleData.startColor.x * Laya.MathUtil.lerp(minConstantColor.x, maxConstantColor.x, colorRandom); ShurikenParticleData.startColor.y = ShurikenParticleData.startColor.y * Laya.MathUtil.lerp(minConstantColor.y, maxConstantColor.y, colorRandom); ShurikenParticleData.startColor.z = ShurikenParticleData.startColor.z * Laya.MathUtil.lerp(minConstantColor.z, maxConstantColor.z, colorRandom); ShurikenParticleData.startColor.w = ShurikenParticleData.startColor.w * Laya.MathUtil.lerp(minConstantColor.w, maxConstantColor.w, colorRandom); break; } } var particleSize = ShurikenParticleData.startSize; switch (particleSystem.startSizeType) { case 0: if (particleSystem.threeDStartSize) { var startSizeConstantSeparate = particleSystem.startSizeConstantSeparate; particleSize[0] = startSizeConstantSeparate.x; particleSize[1] = startSizeConstantSeparate.y; particleSize[2] = startSizeConstantSeparate.z; } else { particleSize[0] = particleSize[1] = particleSize[2] = particleSystem.startSizeConstant; } break; case 2: if (particleSystem.threeDStartSize) { var startSizeConstantMinSeparate = particleSystem.startSizeConstantMinSeparate; var startSizeConstantMaxSeparate = particleSystem.startSizeConstantMaxSeparate; if (autoRandomSeed) { particleSize[0] = Laya.MathUtil.lerp(startSizeConstantMinSeparate.x, startSizeConstantMaxSeparate.x, Math.random()); particleSize[1] = Laya.MathUtil.lerp(startSizeConstantMinSeparate.y, startSizeConstantMaxSeparate.y, Math.random()); particleSize[2] = Laya.MathUtil.lerp(startSizeConstantMinSeparate.z, startSizeConstantMaxSeparate.z, Math.random()); } else { rand.seed = randomSeeds[4]; particleSize[0] = Laya.MathUtil.lerp(startSizeConstantMinSeparate.x, startSizeConstantMaxSeparate.x, rand.getFloat()); particleSize[1] = Laya.MathUtil.lerp(startSizeConstantMinSeparate.y, startSizeConstantMaxSeparate.y, rand.getFloat()); particleSize[2] = Laya.MathUtil.lerp(startSizeConstantMinSeparate.z, startSizeConstantMaxSeparate.z, rand.getFloat()); randomSeeds[4] = rand.seed; } } else { if (autoRandomSeed) { particleSize[0] = particleSize[1] = particleSize[2] = Laya.MathUtil.lerp(particleSystem.startSizeConstantMin, particleSystem.startSizeConstantMax, Math.random()); } else { rand.seed = randomSeeds[4]; particleSize[0] = particleSize[1] = particleSize[2] = Laya.MathUtil.lerp(particleSystem.startSizeConstantMin, particleSystem.startSizeConstantMax, rand.getFloat()); randomSeeds[4] = rand.seed; } } break; } var sizeOverLifetime = particleSystem.sizeOverLifetime; if (sizeOverLifetime && sizeOverLifetime.enable && sizeOverLifetime.size.type === 1) { var size = sizeOverLifetime.size; if (size.separateAxes) { if (autoRandomSeed) { particleSize[0] = particleSize[0] * Laya.MathUtil.lerp(size.constantMinSeparate.x, size.constantMaxSeparate.x, Math.random()); particleSize[1] = particleSize[1] * Laya.MathUtil.lerp(size.constantMinSeparate.y, size.constantMaxSeparate.y, Math.random()); particleSize[2] = particleSize[2] * Laya.MathUtil.lerp(size.constantMinSeparate.z, size.constantMaxSeparate.z, Math.random()); } else { rand.seed = randomSeeds[11]; particleSize[0] = particleSize[0] * Laya.MathUtil.lerp(size.constantMinSeparate.x, size.constantMaxSeparate.x, rand.getFloat()); particleSize[1] = particleSize[1] * Laya.MathUtil.lerp(size.constantMinSeparate.y, size.constantMaxSeparate.y, rand.getFloat()); particleSize[2] = particleSize[2] * Laya.MathUtil.lerp(size.constantMinSeparate.z, size.constantMaxSeparate.z, rand.getFloat()); randomSeeds[11] = rand.seed; } } else { var randomSize; if (autoRandomSeed) { randomSize = Laya.MathUtil.lerp(size.constantMin, size.constantMax, Math.random()); } else { rand.seed = randomSeeds[11]; randomSize = Laya.MathUtil.lerp(size.constantMin, size.constantMax, rand.getFloat()); randomSeeds[11] = rand.seed; } particleSize[0] = particleSize[0] * randomSize; particleSize[1] = particleSize[1] * randomSize; particleSize[2] = particleSize[2] * randomSize; } } var renderMode = particleRender.renderMode; if (renderMode !== 1) { switch (particleSystem.startRotationType) { case 0: if (particleSystem.threeDStartRotation) { var startRotationConstantSeparate = particleSystem.startRotationConstantSeparate; var randomRotationE = ShurikenParticleData._tempVector30; ShurikenParticleData._randomInvertRoationArray(startRotationConstantSeparate, randomRotationE, particleSystem.randomizeRotationDirection, autoRandomSeed ? null : rand, randomSeeds); ShurikenParticleData.startRotation[0] = randomRotationE.x; ShurikenParticleData.startRotation[1] = randomRotationE.y; if (renderMode !== 4) ShurikenParticleData.startRotation[2] = -randomRotationE.z; else ShurikenParticleData.startRotation[2] = randomRotationE.z; } else { ShurikenParticleData.startRotation[0] = ShurikenParticleData._randomInvertRoation(particleSystem.startRotationConstant, particleSystem.randomizeRotationDirection, autoRandomSeed ? null : rand, randomSeeds); ShurikenParticleData.startRotation[1] = 0; ShurikenParticleData.startRotation[2] = 0; } break; case 2: if (particleSystem.threeDStartRotation) { var startRotationConstantMinSeparate = particleSystem.startRotationConstantMinSeparate; var startRotationConstantMaxSeparate = particleSystem.startRotationConstantMaxSeparate; var lerpRoationE = ShurikenParticleData._tempVector30; if (autoRandomSeed) { lerpRoationE.x = Laya.MathUtil.lerp(startRotationConstantMinSeparate.x, startRotationConstantMaxSeparate.x, Math.random()); lerpRoationE.y = Laya.MathUtil.lerp(startRotationConstantMinSeparate.y, startRotationConstantMaxSeparate.y, Math.random()); lerpRoationE.z = Laya.MathUtil.lerp(startRotationConstantMinSeparate.z, startRotationConstantMaxSeparate.z, Math.random()); } else { rand.seed = randomSeeds[5]; lerpRoationE.x = Laya.MathUtil.lerp(startRotationConstantMinSeparate.x, startRotationConstantMaxSeparate.x, rand.getFloat()); lerpRoationE.y = Laya.MathUtil.lerp(startRotationConstantMinSeparate.y, startRotationConstantMaxSeparate.y, rand.getFloat()); lerpRoationE.z = Laya.MathUtil.lerp(startRotationConstantMinSeparate.z, startRotationConstantMaxSeparate.z, rand.getFloat()); randomSeeds[5] = rand.seed; } ShurikenParticleData._randomInvertRoationArray(lerpRoationE, lerpRoationE, particleSystem.randomizeRotationDirection, autoRandomSeed ? null : rand, randomSeeds); ShurikenParticleData.startRotation[0] = lerpRoationE.x; ShurikenParticleData.startRotation[1] = lerpRoationE.y; if (renderMode !== 4) ShurikenParticleData.startRotation[2] = -lerpRoationE.z; else ShurikenParticleData.startRotation[2] = lerpRoationE.z; } else { if (autoRandomSeed) { ShurikenParticleData.startRotation[0] = ShurikenParticleData._randomInvertRoation(Laya.MathUtil.lerp(particleSystem.startRotationConstantMin, particleSystem.startRotationConstantMax, Math.random()), particleSystem.randomizeRotationDirection, autoRandomSeed ? null : rand, randomSeeds); } else { rand.seed = randomSeeds[5]; ShurikenParticleData.startRotation[0] = ShurikenParticleData._randomInvertRoation(Laya.MathUtil.lerp(particleSystem.startRotationConstantMin, particleSystem.startRotationConstantMax, rand.getFloat()), particleSystem.randomizeRotationDirection, autoRandomSeed ? null : rand, randomSeeds); randomSeeds[5] = rand.seed; } } break; } } switch (particleSystem.startLifetimeType) { case 0: ShurikenParticleData.startLifeTime = particleSystem.startLifetimeConstant; break; case 1: ShurikenParticleData.startLifeTime = ShurikenParticleData._getStartLifetimeFromGradient(particleSystem.startLifeTimeGradient, particleSystem.emissionTime); break; case 2: if (autoRandomSeed) { ShurikenParticleData.startLifeTime = Laya.MathUtil.lerp(particleSystem.startLifetimeConstantMin, particleSystem.startLifetimeConstantMax, Math.random()); } else { rand.seed = randomSeeds[7]; ShurikenParticleData.startLifeTime = Laya.MathUtil.lerp(particleSystem.startLifetimeConstantMin, particleSystem.startLifetimeConstantMax, rand.getFloat()); randomSeeds[7] = rand.seed; } break; case 3: var emissionTime = particleSystem.emissionTime; if (autoRandomSeed) { ShurikenParticleData.startLifeTime = Laya.MathUtil.lerp(ShurikenParticleData._getStartLifetimeFromGradient(particleSystem.startLifeTimeGradientMin, emissionTime), ShurikenParticleData._getStartLifetimeFromGradient(particleSystem.startLifeTimeGradientMax, emissionTime), Math.random()); } else { rand.seed = randomSeeds[7]; ShurikenParticleData.startLifeTime = Laya.MathUtil.lerp(ShurikenParticleData._getStartLifetimeFromGradient(particleSystem.startLifeTimeGradientMin, emissionTime), ShurikenParticleData._getStartLifetimeFromGradient(particleSystem.startLifeTimeGradientMax, emissionTime), rand.getFloat()); randomSeeds[7] = rand.seed; } break; } var textureSheetAnimation = particleSystem.textureSheetAnimation; var enableSheetAnimation = textureSheetAnimation && textureSheetAnimation.enable; if (enableSheetAnimation) { var title = textureSheetAnimation.tiles; var titleX = title.x, titleY = title.y; var subU = 1.0 / titleX, subV = 1.0 / titleY; var startFrameCount; var startFrame = textureSheetAnimation.startFrame; switch (startFrame.type) { case 0: startFrameCount = startFrame.constant; break; case 1: if (autoRandomSeed) { startFrameCount = Laya.MathUtil.lerp(startFrame.constantMin, startFrame.constantMax, Math.random()); } else { rand.seed = randomSeeds[14]; startFrameCount = Laya.MathUtil.lerp(startFrame.constantMin, startFrame.constantMax, rand.getFloat()); randomSeeds[14] = rand.seed; } break; } var frame = textureSheetAnimation.frame; var cycles = textureSheetAnimation.cycles; switch (frame.type) { case 0: startFrameCount += frame.constant * cycles; break; case 2: if (autoRandomSeed) { startFrameCount += Laya.MathUtil.lerp(frame.constantMin, frame.constantMax, Math.random()) * cycles; } else { rand.seed = randomSeeds[15]; startFrameCount += Laya.MathUtil.lerp(frame.constantMin, frame.constantMax, rand.getFloat()) * cycles; randomSeeds[15] = rand.seed; } break; } var startRow = 0; switch (textureSheetAnimation.type) { case 0: startRow = Math.floor(startFrameCount / titleX); break; case 1: if (textureSheetAnimation.randomRow) { if (autoRandomSeed) { startRow = Math.floor(Math.random() * titleY); } else { rand.seed = randomSeeds[13]; startRow = Math.floor(rand.getFloat() * titleY); randomSeeds[13] = rand.seed; } } else { startRow = textureSheetAnimation.rowIndex; } break; } var startCol = Math.floor(startFrameCount % titleX); ShurikenParticleData.startUVInfo = ShurikenParticleData.startUVInfo; ShurikenParticleData.startUVInfo[0] = subU; ShurikenParticleData.startUVInfo[1] = subV; ShurikenParticleData.startUVInfo[2] = startCol * subU; ShurikenParticleData.startUVInfo[3] = startRow * subV; } else { ShurikenParticleData.startUVInfo = ShurikenParticleData.startUVInfo; ShurikenParticleData.startUVInfo[0] = 1.0; ShurikenParticleData.startUVInfo[1] = 1.0; ShurikenParticleData.startUVInfo[2] = 0.0; ShurikenParticleData.startUVInfo[3] = 0.0; } } } ShurikenParticleData._tempVector30 = new Vector3(); ShurikenParticleData.startColor = new Vector4(); ShurikenParticleData.startSize = new Float32Array(3); ShurikenParticleData.startRotation = new Float32Array(3); ShurikenParticleData.startUVInfo = new Float32Array(4); class ShurikenParticleSystem extends GeometryElement { constructor(owner) { super(); this._boundingSphere = null; this._boundingBox = null; this._boundingBoxCorners = null; this._owner = null; this._ownerRender = null; this._vertices = null; this._floatCountPerVertex = 0; this._startLifeTimeIndex = 0; this._timeIndex = 0; this._simulateUpdate = false; this._firstActiveElement = 0; this._firstNewElement = 0; this._firstFreeElement = 0; this._firstRetiredElement = 0; this._drawCounter = 0; this._bufferMaxParticles = 0; this._emission = null; this._shape = null; this._isEmitting = false; this._isPlaying = false; this._isPaused = false; this._playStartDelay = 0; this._frameRateTime = 0; this._emissionTime = 0; this._totalDelayTime = 0; this._burstsIndex = 0; this._velocityOverLifetime = null; this._colorOverLifetime = null; this._sizeOverLifetime = null; this._rotationOverLifetime = null; this._textureSheetAnimation = null; this._startLifetimeType = 0; this._startLifetimeConstant = 0; this._startLifeTimeGradient = null; this._startLifetimeConstantMin = 0; this._startLifetimeConstantMax = 0; this._startLifeTimeGradientMin = null; this._startLifeTimeGradientMax = null; this._maxStartLifetime = 0; this._uvLength = new Vector2(); this._vertexStride = 0; this._indexStride = 0; this._vertexBuffer = null; this._indexBuffer = null; this._bufferState = new BufferState(); this._currentTime = 0; this._startUpdateLoopCount = 0; this._rand = null; this._randomSeeds = null; this.duration = 0; this.looping = false; this.prewarm = false; this.startDelayType = 0; this.startDelay = 0; this.startDelayMin = 0; this.startDelayMax = 0; this.startSpeedType = 0; this.startSpeedConstant = 0; this.startSpeedConstantMin = 0; this.startSpeedConstantMax = 0; this.threeDStartSize = false; this.startSizeType = 0; this.startSizeConstant = 0; this.startSizeConstantSeparate = null; this.startSizeConstantMin = 0; this.startSizeConstantMax = 0; this.startSizeConstantMinSeparate = null; this.startSizeConstantMaxSeparate = null; this.threeDStartRotation = false; this.startRotationType = 0; this.startRotationConstant = 0; this.startRotationConstantSeparate = null; this.startRotationConstantMin = 0; this.startRotationConstantMax = 0; this.startRotationConstantMinSeparate = null; this.startRotationConstantMaxSeparate = null; this.randomizeRotationDirection = 0; this.startColorType = 0; this.startColorConstant = new Vector4(1, 1, 1, 1); this.startColorConstantMin = new Vector4(0, 0, 0, 0); this.startColorConstantMax = new Vector4(1, 1, 1, 1); this.gravityModifier = 0; this.simulationSpace = 0; this.simulationSpeed = 1.0; this.scaleMode = 1; this.playOnAwake = false; this.randomSeed = null; this.autoRandomSeed = false; this.isPerformanceMode = false; this._firstActiveElement = 0; this._firstNewElement = 0; this._firstFreeElement = 0; this._firstRetiredElement = 0; this._owner = owner; this._ownerRender = owner.particleRenderer; this._boundingBoxCorners = []; this._boundingSphere = new BoundSphere(new Vector3(), Number.MAX_VALUE); this._boundingBox = new BoundBox(new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE), new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE)); this._currentTime = 0; this._isEmitting = false; this._isPlaying = false; this._isPaused = false; this._burstsIndex = 0; this._frameRateTime = 0; this._emissionTime = 0; this._totalDelayTime = 0; this._simulateUpdate = false; this._bufferMaxParticles = 1; this.duration = 5.0; this.looping = true; this.prewarm = false; this.startDelayType = 0; this.startDelay = 0.0; this.startDelayMin = 0.0; this.startDelayMax = 0.0; this._startLifetimeType = 0; this._startLifetimeConstant = 5.0; this._startLifeTimeGradient = new GradientDataNumber(); this._startLifetimeConstantMin = 0.0; this._startLifetimeConstantMax = 5.0; this._startLifeTimeGradientMin = new GradientDataNumber(); this._startLifeTimeGradientMax = new GradientDataNumber(); this._maxStartLifetime = 5.0; this.startSpeedType = 0; this.startSpeedConstant = 5.0; this.startSpeedConstantMin = 0.0; this.startSpeedConstantMax = 5.0; this.threeDStartSize = false; this.startSizeType = 0; this.startSizeConstant = 1; this.startSizeConstantSeparate = new Vector3(1, 1, 1); this.startSizeConstantMin = 0; this.startSizeConstantMax = 1; this.startSizeConstantMinSeparate = new Vector3(0, 0, 0); this.startSizeConstantMaxSeparate = new Vector3(1, 1, 1); this.threeDStartRotation = false; this.startRotationType = 0; this.startRotationConstant = 0; this.startRotationConstantSeparate = new Vector3(0, 0, 0); this.startRotationConstantMin = 0.0; this.startRotationConstantMax = 0.0; this.startRotationConstantMinSeparate = new Vector3(0, 0, 0); this.startRotationConstantMaxSeparate = new Vector3(0, 0, 0); this.gravityModifier = 0.0; this.simulationSpace = 1; this.scaleMode = 1; this.playOnAwake = true; this._rand = new Rand(0); this.autoRandomSeed = true; this.randomSeed = new Uint32Array(1); this._randomSeeds = new Uint32Array(ShurikenParticleSystem._RANDOMOFFSET.length); this.isPerformanceMode = true; this._emission = new Emission(); this._emission.enable = true; } ; get maxParticles() { return this._bufferMaxParticles - 1; } set maxParticles(value) { var newMaxParticles = value + 1; if (newMaxParticles !== this._bufferMaxParticles) { this._bufferMaxParticles = newMaxParticles; this._initBufferDatas(); } } get emission() { return this._emission; } get aliveParticleCount() { if (this._firstNewElement >= this._firstRetiredElement) return this._firstNewElement - this._firstRetiredElement; else return this._bufferMaxParticles - this._firstRetiredElement + this._firstNewElement; } get emissionTime() { return this._emissionTime > this.duration ? this.duration : this._emissionTime; } get shape() { return this._shape; } set shape(value) { if (this._shape !== value) { if (value && value.enable) this._owner._render._shaderValues.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SHAPE); else this._owner._render._shaderValues.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SHAPE); this._shape = value; } } get isAlive() { if (this._isPlaying || this.aliveParticleCount > 0) return true; return false; } get isEmitting() { return this._isEmitting; } get isPlaying() { return this._isPlaying; } get isPaused() { return this._isPaused; } get startLifetimeType() { return this._startLifetimeType; } set startLifetimeType(value) { var i, n; switch (this.startLifetimeType) { case 0: this._maxStartLifetime = this.startLifetimeConstant; break; case 1: this._maxStartLifetime = -Number.MAX_VALUE; var startLifeTimeGradient = startLifeTimeGradient; for (i = 0, n = startLifeTimeGradient.gradientCount; i < n; i++) this._maxStartLifetime = Math.max(this._maxStartLifetime, startLifeTimeGradient.getValueByIndex(i)); break; case 2: this._maxStartLifetime = Math.max(this.startLifetimeConstantMin, this.startLifetimeConstantMax); break; case 3: this._maxStartLifetime = -Number.MAX_VALUE; var startLifeTimeGradientMin = startLifeTimeGradientMin; for (i = 0, n = startLifeTimeGradientMin.gradientCount; i < n; i++) this._maxStartLifetime = Math.max(this._maxStartLifetime, startLifeTimeGradientMin.getValueByIndex(i)); var startLifeTimeGradientMax = startLifeTimeGradientMax; for (i = 0, n = startLifeTimeGradientMax.gradientCount; i < n; i++) this._maxStartLifetime = Math.max(this._maxStartLifetime, startLifeTimeGradientMax.getValueByIndex(i)); break; } this._startLifetimeType = value; } get startLifetimeConstant() { return this._startLifetimeConstant; } set startLifetimeConstant(value) { if (this._startLifetimeType === 0) this._maxStartLifetime = value; this._startLifetimeConstant = value; } get startLifeTimeGradient() { return this._startLifeTimeGradient; } set startLifeTimeGradient(value) { if (this._startLifetimeType === 1) { this._maxStartLifetime = -Number.MAX_VALUE; for (var i = 0, n = value.gradientCount; i < n; i++) this._maxStartLifetime = Math.max(this._maxStartLifetime, value.getValueByIndex(i)); } this._startLifeTimeGradient = value; } get startLifetimeConstantMin() { return this._startLifetimeConstantMin; } set startLifetimeConstantMin(value) { if (this._startLifetimeType === 2) this._maxStartLifetime = Math.max(value, this._startLifetimeConstantMax); this._startLifetimeConstantMin = value; } get startLifetimeConstantMax() { return this._startLifetimeConstantMax; } set startLifetimeConstantMax(value) { if (this._startLifetimeType === 2) this._maxStartLifetime = Math.max(this._startLifetimeConstantMin, value); this._startLifetimeConstantMax = value; } get startLifeTimeGradientMin() { return this._startLifeTimeGradientMin; } set startLifeTimeGradientMin(value) { if (this._startLifetimeType === 3) { var i, n; this._maxStartLifetime = -Number.MAX_VALUE; for (i = 0, n = value.gradientCount; i < n; i++) this._maxStartLifetime = Math.max(this._maxStartLifetime, value.getValueByIndex(i)); for (i = 0, n = this._startLifeTimeGradientMax.gradientCount; i < n; i++) this._maxStartLifetime = Math.max(this._maxStartLifetime, this._startLifeTimeGradientMax.getValueByIndex(i)); } this._startLifeTimeGradientMin = value; } get startLifeTimeGradientMax() { return this._startLifeTimeGradientMax; } set startLifeTimeGradientMax(value) { if (this._startLifetimeType === 3) { var i, n; this._maxStartLifetime = -Number.MAX_VALUE; for (i = 0, n = this._startLifeTimeGradientMin.gradientCount; i < n; i++) this._maxStartLifetime = Math.max(this._maxStartLifetime, this._startLifeTimeGradientMin.getValueByIndex(i)); for (i = 0, n = value.gradientCount; i < n; i++) this._maxStartLifetime = Math.max(this._maxStartLifetime, value.getValueByIndex(i)); } this._startLifeTimeGradientMax = value; } get velocityOverLifetime() { return this._velocityOverLifetime; } set velocityOverLifetime(value) { var shaDat = this._owner._render._shaderValues; if (value) { var velocity = value.velocity; var velocityType = velocity.type; if (value.enable) { switch (velocityType) { case 0: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMECONSTANT); break; case 1: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMECURVE); break; case 2: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMERANDOMCONSTANT); break; case 3: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMERANDOMCURVE); break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMECONSTANT); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMECURVE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMERANDOMCONSTANT); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMERANDOMCURVE); } switch (velocityType) { case 0: shaDat.setVector3(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYCONST, velocity.constant); break; case 1: shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTX, velocity.gradientX._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTY, velocity.gradientY._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTZ, velocity.gradientZ._elements); break; case 2: shaDat.setVector3(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYCONST, velocity.constantMin); shaDat.setVector3(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYCONSTMAX, velocity.constantMax); break; case 3: shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTX, velocity.gradientXMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTXMAX, velocity.gradientXMax._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTY, velocity.gradientYMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTYMAX, velocity.gradientYMax._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTZ, velocity.gradientZMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.VOLVELOCITYGRADIENTZMAX, velocity.gradientZMax._elements); break; } shaDat.setInt(ShuriKenParticle3DShaderDeclaration.VOLSPACETYPE, value.space); } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMECONSTANT); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMECURVE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMERANDOMCONSTANT); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMERANDOMCURVE); } this._velocityOverLifetime = value; } get colorOverLifetime() { return this._colorOverLifetime; } set colorOverLifetime(value) { var shaDat = this._owner._render._shaderValues; if (value) { var color = value.color; if (value.enable) { switch (color.type) { case 1: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_COLOROVERLIFETIME); break; case 3: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RANDOMCOLOROVERLIFETIME); break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_COLOROVERLIFETIME); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RANDOMCOLOROVERLIFETIME); } switch (color.type) { case 1: var gradientColor = color.gradient; shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTALPHAS, gradientColor._alphaElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTCOLORS, gradientColor._rgbElements); break; case 3: var minGradientColor = color.gradientMin; var maxGradientColor = color.gradientMax; shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTALPHAS, minGradientColor._alphaElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTCOLORS, minGradientColor._rgbElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.MAXCOLOROVERLIFEGRADIENTALPHAS, maxGradientColor._alphaElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.MAXCOLOROVERLIFEGRADIENTCOLORS, maxGradientColor._rgbElements); break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_COLOROVERLIFETIME); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RANDOMCOLOROVERLIFETIME); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTALPHAS, gradientColor._alphaElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTCOLORS, gradientColor._rgbElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTALPHAS, minGradientColor._alphaElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.COLOROVERLIFEGRADIENTCOLORS, minGradientColor._rgbElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.MAXCOLOROVERLIFEGRADIENTALPHAS, maxGradientColor._alphaElements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.MAXCOLOROVERLIFEGRADIENTCOLORS, maxGradientColor._rgbElements); } this._colorOverLifetime = value; } get sizeOverLifetime() { return this._sizeOverLifetime; } set sizeOverLifetime(value) { var shaDat = this._owner._render._shaderValues; if (value) { var size = value.size; var sizeSeparate = size.separateAxes; var sizeType = size.type; if (value.enable) { switch (sizeType) { case 0: if (sizeSeparate) shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMECURVESEPERATE); else shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMECURVE); break; case 2: if (sizeSeparate) shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMERANDOMCURVESSEPERATE); else shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMERANDOMCURVES); break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMECURVE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMECURVESEPERATE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMERANDOMCURVES); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMERANDOMCURVESSEPERATE); } switch (sizeType) { case 0: if (sizeSeparate) { shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTX, size.gradientX._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTY, size.gradientY._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSizeGradientZ, size.gradientZ._elements); } else { shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENT, size.gradient._elements); } break; case 2: if (sizeSeparate) { shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTX, size.gradientXMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTXMAX, size.gradientXMax._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTY, size.gradientYMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENTYMAX, size.gradientYMax._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSizeGradientZ, size.gradientZMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSizeGradientZMAX, size.gradientZMax._elements); } else { shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSIZEGRADIENT, size.gradientMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.SOLSizeGradientMax, size.gradientMax._elements); } break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMECURVE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMECURVESEPERATE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMERANDOMCURVES); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMERANDOMCURVESSEPERATE); } this._sizeOverLifetime = value; } get rotationOverLifetime() { return this._rotationOverLifetime; } set rotationOverLifetime(value) { var shaDat = this._owner._render._shaderValues; if (value) { var rotation = value.angularVelocity; if (!rotation) return; var rotationSeparate = rotation.separateAxes; var rotationType = rotation.type; if (value.enable) { if (rotationSeparate) shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMESEPERATE); else shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIME); switch (rotationType) { case 0: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMECONSTANT); break; case 1: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMECURVE); break; case 2: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMERANDOMCONSTANTS); break; case 3: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMERANDOMCURVES); break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIME); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMESEPERATE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMECONSTANT); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMECURVE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMERANDOMCONSTANTS); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMERANDOMCURVES); } switch (rotationType) { case 0: if (rotationSeparate) { shaDat.setVector3(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONSTSEPRARATE, rotation.constantSeparate); } else { shaDat.setNumber(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONST, rotation.constant); } break; case 1: if (rotationSeparate) { shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTX, rotation.gradientX._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTY, rotation.gradientY._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTZ, rotation.gradientZ._elements); } else { shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENT, rotation.gradient._elements); } break; case 2: if (rotationSeparate) { shaDat.setVector3(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONSTSEPRARATE, rotation.constantMinSeparate); shaDat.setVector3(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONSTMAXSEPRARATE, rotation.constantMaxSeparate); } else { shaDat.setNumber(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONST, rotation.constantMin); shaDat.setNumber(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYCONSTMAX, rotation.constantMax); } break; case 3: if (rotationSeparate) { shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTX, rotation.gradientXMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTXMAX, rotation.gradientXMax._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTY, rotation.gradientYMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTYMAX, rotation.gradientYMax._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTZ, rotation.gradientZMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTZMAX, rotation.gradientZMax._elements); } else { shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENT, rotation.gradientMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.ROLANGULARVELOCITYGRADIENTMAX, rotation.gradientMax._elements); } break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIME); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMESEPERATE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMECONSTANT); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMECURVE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMERANDOMCONSTANTS); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMERANDOMCURVES); } this._rotationOverLifetime = value; } get textureSheetAnimation() { return this._textureSheetAnimation; } set textureSheetAnimation(value) { var shaDat = this._owner._render._shaderValues; if (value) { var frameOverTime = value.frame; var textureAniType = frameOverTime.type; if (value.enable) { switch (textureAniType) { case 1: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_TEXTURESHEETANIMATIONCURVE); break; case 3: shaDat.addDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_TEXTURESHEETANIMATIONRANDOMCURVE); break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_TEXTURESHEETANIMATIONCURVE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_TEXTURESHEETANIMATIONRANDOMCURVE); } if (textureAniType === 1 || textureAniType === 3) { shaDat.setNumber(ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONCYCLES, value.cycles); var title = value.tiles; var _uvLengthE = this._uvLength; _uvLengthE.x = 1.0 / title.x; _uvLengthE.y = 1.0 / title.y; shaDat.setVector2(ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONSUBUVLENGTH, this._uvLength); } switch (textureAniType) { case 1: shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONGRADIENTUVS, frameOverTime.frameOverTimeData._elements); break; case 3: shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONGRADIENTUVS, frameOverTime.frameOverTimeDataMin._elements); shaDat.setBuffer(ShuriKenParticle3DShaderDeclaration.TEXTURESHEETANIMATIONGRADIENTMAXUVS, frameOverTime.frameOverTimeDataMax._elements); break; } } else { shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_TEXTURESHEETANIMATIONCURVE); shaDat.removeDefine(ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_TEXTURESHEETANIMATIONRANDOMCURVE); } this._textureSheetAnimation = value; } _getVertexBuffer(index = 0) { if (index === 0) return this._vertexBuffer; else return null; } _getIndexBuffer() { return this._indexBuffer; } _generateBoundingSphere() { var centerE = this._boundingSphere.center; centerE.x = 0; centerE.y = 0; centerE.z = 0; this._boundingSphere.radius = Number.MAX_VALUE; } _generateBoundingBox() { var particle = this._owner; var particleRender = particle.particleRenderer; var boundMin = this._boundingBox.min; var boundMax = this._boundingBox.max; var i, n; var maxStartLifeTime; switch (this.startLifetimeType) { case 0: maxStartLifeTime = this.startLifetimeConstant; break; case 1: maxStartLifeTime = -Number.MAX_VALUE; var startLifeTimeGradient = startLifeTimeGradient; for (i = 0, n = startLifeTimeGradient.gradientCount; i < n; i++) maxStartLifeTime = Math.max(maxStartLifeTime, startLifeTimeGradient.getValueByIndex(i)); break; case 2: maxStartLifeTime = Math.max(this.startLifetimeConstantMin, this.startLifetimeConstantMax); break; case 3: maxStartLifeTime = -Number.MAX_VALUE; var startLifeTimeGradientMin = startLifeTimeGradientMin; for (i = 0, n = startLifeTimeGradientMin.gradientCount; i < n; i++) maxStartLifeTime = Math.max(maxStartLifeTime, startLifeTimeGradientMin.getValueByIndex(i)); var startLifeTimeGradientMax = startLifeTimeGradientMax; for (i = 0, n = startLifeTimeGradientMax.gradientCount; i < n; i++) maxStartLifeTime = Math.max(maxStartLifeTime, startLifeTimeGradientMax.getValueByIndex(i)); break; } var minStartSpeed, maxStartSpeed; switch (this.startSpeedType) { case 0: minStartSpeed = maxStartSpeed = this.startSpeedConstant; break; case 1: break; case 2: minStartSpeed = this.startLifetimeConstantMin; maxStartSpeed = this.startLifetimeConstantMax; break; case 3: break; } var minPosition, maxPosition, minDirection, maxDirection; if (this._shape && this._shape.enable) ; else { minPosition = maxPosition = Vector3._ZERO; minDirection = Vector3._ZERO; maxDirection = Vector3._UnitZ; } var startMinVelocity = new Vector3(minDirection.x * minStartSpeed, minDirection.y * minStartSpeed, minDirection.z * minStartSpeed); var startMaxVelocity = new Vector3(maxDirection.x * maxStartSpeed, maxDirection.y * maxStartSpeed, maxDirection.z * maxStartSpeed); if (this._velocityOverLifetime && this._velocityOverLifetime.enable) { var lifeMinVelocity; var lifeMaxVelocity; var velocity = this._velocityOverLifetime.velocity; switch (velocity.type) { case 0: lifeMinVelocity = lifeMaxVelocity = velocity.constant; break; case 1: lifeMinVelocity = lifeMaxVelocity = new Vector3(velocity.gradientX.getAverageValue(), velocity.gradientY.getAverageValue(), velocity.gradientZ.getAverageValue()); break; case 2: lifeMinVelocity = velocity.constantMin; lifeMaxVelocity = velocity.constantMax; break; case 3: lifeMinVelocity = new Vector3(velocity.gradientXMin.getAverageValue(), velocity.gradientYMin.getAverageValue(), velocity.gradientZMin.getAverageValue()); lifeMaxVelocity = new Vector3(velocity.gradientXMax.getAverageValue(), velocity.gradientYMax.getAverageValue(), velocity.gradientZMax.getAverageValue()); break; } } var positionScale, velocityScale; var transform = this._owner.transform; var worldPosition = transform.position; var sizeScale = ShurikenParticleSystem._tempVector39; var renderMode = particleRender.renderMode; switch (this.scaleMode) { case 0: var scale = transform.getWorldLossyScale(); positionScale = scale; sizeScale.x = scale.x; sizeScale.y = scale.z; sizeScale.z = scale.y; (renderMode === 1) && (velocityScale = scale); break; case 1: var localScale = transform.localScale; positionScale = localScale; sizeScale.x = localScale.x; sizeScale.y = localScale.z; sizeScale.z = localScale.y; (renderMode === 1) && (velocityScale = localScale); break; case 2: positionScale = transform.getWorldLossyScale(); sizeScale.x = sizeScale.y = sizeScale.z = 1; (renderMode === 1) && (velocityScale = Vector3._ONE); break; } var minStratPosition, maxStratPosition; if (this._velocityOverLifetime && this._velocityOverLifetime.enable) ; else { minStratPosition = new Vector3(startMinVelocity.x * maxStartLifeTime, startMinVelocity.y * maxStartLifeTime, startMinVelocity.z * maxStartLifeTime); maxStratPosition = new Vector3(startMaxVelocity.x * maxStartLifeTime, startMaxVelocity.y * maxStartLifeTime, startMaxVelocity.z * maxStartLifeTime); if (this.scaleMode != 2) { Vector3.add(minPosition, minStratPosition, boundMin); Vector3.multiply(positionScale, boundMin, boundMin); Vector3.add(maxPosition, maxStratPosition, boundMax); Vector3.multiply(positionScale, boundMax, boundMax); } else { Vector3.multiply(positionScale, minPosition, boundMin); Vector3.add(boundMin, minStratPosition, boundMin); Vector3.multiply(positionScale, maxPosition, boundMax); Vector3.add(boundMax, maxStratPosition, boundMax); } } switch (this.simulationSpace) { case 0: break; case 1: Vector3.add(boundMin, worldPosition, boundMin); Vector3.add(boundMax, worldPosition, boundMax); break; } var maxSize, maxSizeY; switch (this.startSizeType) { case 0: if (this.threeDStartSize) { var startSizeConstantSeparate = startSizeConstantSeparate; maxSize = Math.max(startSizeConstantSeparate.x, startSizeConstantSeparate.y); if (renderMode === 1) maxSizeY = startSizeConstantSeparate.y; } else { maxSize = this.startSizeConstant; if (renderMode === 1) maxSizeY = this.startSizeConstant; } break; case 1: break; case 2: if (this.threeDStartSize) { var startSizeConstantMaxSeparate = startSizeConstantMaxSeparate; maxSize = Math.max(startSizeConstantMaxSeparate.x, startSizeConstantMaxSeparate.y); if (renderMode === 1) maxSizeY = startSizeConstantMaxSeparate.y; } else { maxSize = this.startSizeConstantMax; if (renderMode === 1) maxSizeY = this.startSizeConstantMax; } break; case 3: break; } if (this._sizeOverLifetime && this._sizeOverLifetime.enable) { var size = this._sizeOverLifetime.size; maxSize *= this._sizeOverLifetime.size.getMaxSizeInGradient(); } var threeDMaxSize = ShurikenParticleSystem._tempVector30; var rotSize, nonRotSize; switch (renderMode) { case 0: rotSize = maxSize * ShurikenParticleSystem.halfKSqrtOf2; Vector3.scale(sizeScale, maxSize, threeDMaxSize); Vector3.subtract(boundMin, threeDMaxSize, boundMin); Vector3.add(boundMax, threeDMaxSize, boundMax); break; case 1: var maxStretchPosition = ShurikenParticleSystem._tempVector31; var maxStretchVelocity = ShurikenParticleSystem._tempVector32; var minStretchVelocity = ShurikenParticleSystem._tempVector33; var minStretchPosition = ShurikenParticleSystem._tempVector34; if (this._velocityOverLifetime && this._velocityOverLifetime.enable) ; else { Vector3.multiply(velocityScale, startMaxVelocity, maxStretchVelocity); Vector3.multiply(velocityScale, startMinVelocity, minStretchVelocity); } var sizeStretch = maxSizeY * particleRender.stretchedBillboardLengthScale; var maxStretchLength = Vector3.scalarLength(maxStretchVelocity) * particleRender.stretchedBillboardSpeedScale + sizeStretch; var minStretchLength = Vector3.scalarLength(minStretchVelocity) * particleRender.stretchedBillboardSpeedScale + sizeStretch; var norMaxStretchVelocity = ShurikenParticleSystem._tempVector35; var norMinStretchVelocity = ShurikenParticleSystem._tempVector36; Vector3.normalize(maxStretchVelocity, norMaxStretchVelocity); Vector3.scale(norMaxStretchVelocity, maxStretchLength, minStretchPosition); Vector3.subtract(maxStratPosition, minStretchPosition, minStretchPosition); Vector3.normalize(minStretchVelocity, norMinStretchVelocity); Vector3.scale(norMinStretchVelocity, minStretchLength, maxStretchPosition); Vector3.add(minStratPosition, maxStretchPosition, maxStretchPosition); rotSize = maxSize * ShurikenParticleSystem.halfKSqrtOf2; Vector3.scale(sizeScale, rotSize, threeDMaxSize); var halfNorMaxStretchVelocity = ShurikenParticleSystem._tempVector37; var halfNorMinStretchVelocity = ShurikenParticleSystem._tempVector38; Vector3.scale(norMaxStretchVelocity, 0.5, halfNorMaxStretchVelocity); Vector3.scale(norMinStretchVelocity, 0.5, halfNorMinStretchVelocity); Vector3.multiply(halfNorMaxStretchVelocity, sizeScale, halfNorMaxStretchVelocity); Vector3.multiply(halfNorMinStretchVelocity, sizeScale, halfNorMinStretchVelocity); Vector3.add(boundMin, halfNorMinStretchVelocity, boundMin); Vector3.min(boundMin, minStretchPosition, boundMin); Vector3.subtract(boundMin, threeDMaxSize, boundMin); Vector3.subtract(boundMax, halfNorMaxStretchVelocity, boundMax); Vector3.max(boundMax, maxStretchPosition, boundMax); Vector3.add(boundMax, threeDMaxSize, boundMax); break; case 2: maxSize *= Math.cos(0.78539816339744830961566084581988); nonRotSize = maxSize * 0.5; threeDMaxSize.x = sizeScale.x * nonRotSize; threeDMaxSize.y = sizeScale.z * nonRotSize; Vector3.subtract(boundMin, threeDMaxSize, boundMin); Vector3.add(boundMax, threeDMaxSize, boundMax); break; case 3: maxSize *= Math.cos(0.78539816339744830961566084581988); nonRotSize = maxSize * 0.5; Vector3.scale(sizeScale, nonRotSize, threeDMaxSize); Vector3.subtract(boundMin, threeDMaxSize, boundMin); Vector3.add(boundMax, threeDMaxSize, boundMax); break; } this._boundingBox.getCorners(this._boundingBoxCorners); } _updateEmission() { if (!this.isAlive) return; if (this._simulateUpdate) { this._simulateUpdate = false; } else { var elapsedTime = (this._startUpdateLoopCount !== Laya.Stat.loopCount && !this._isPaused) ? this._owner._scene.timer._delta / 1000.0 : 0; elapsedTime = Math.min(ShurikenParticleSystem._maxElapsedTime, elapsedTime * this.simulationSpeed); this._updateParticles(elapsedTime); } } _updateParticles(elapsedTime) { if (this._ownerRender.renderMode === 4 && !this._ownerRender.mesh) return; this._currentTime += elapsedTime; this._retireActiveParticles(); this._freeRetiredParticles(); this._totalDelayTime += elapsedTime; if (this._totalDelayTime < this._playStartDelay) { return; } if (this._emission.enable && this._isEmitting && !this._isPaused) this._advanceTime(elapsedTime, this._currentTime); } _updateParticlesSimulationRestart(time) { this._firstActiveElement = 0; this._firstNewElement = 0; this._firstFreeElement = 0; this._firstRetiredElement = 0; this._burstsIndex = 0; this._frameRateTime = time; this._emissionTime = 0; this._totalDelayTime = 0; this._currentTime = time; var delayTime = time; if (delayTime < this._playStartDelay) { this._totalDelayTime = delayTime; return; } if (this._emission.enable) this._advanceTime(time, time); } _retireActiveParticles() { const epsilon = 0.0001; while (this._firstActiveElement != this._firstNewElement) { var index = this._firstActiveElement * this._floatCountPerVertex * this._vertexStride; var timeIndex = index + this._timeIndex; var particleAge = this._currentTime - this._vertices[timeIndex]; if (particleAge + epsilon < this._vertices[index + this._startLifeTimeIndex]) break; this._vertices[timeIndex] = this._drawCounter; this._firstActiveElement++; if (this._firstActiveElement >= this._bufferMaxParticles) this._firstActiveElement = 0; } } _freeRetiredParticles() { while (this._firstRetiredElement != this._firstActiveElement) { var age = this._drawCounter - this._vertices[this._firstRetiredElement * this._floatCountPerVertex * this._vertexStride + this._timeIndex]; if (this.isPerformanceMode) if (age < 3) break; this._firstRetiredElement++; if (this._firstRetiredElement >= this._bufferMaxParticles) this._firstRetiredElement = 0; } } _burst(fromTime, toTime) { var totalEmitCount = 0; var bursts = this._emission._bursts; for (var n = bursts.length; this._burstsIndex < n; this._burstsIndex++) { var burst = bursts[this._burstsIndex]; var burstTime = burst.time; if (fromTime <= burstTime && burstTime < toTime) { var emitCount; if (this.autoRandomSeed) { emitCount = Laya.MathUtil.lerp(burst.minCount, burst.maxCount, Math.random()); } else { this._rand.seed = this._randomSeeds[0]; emitCount = Laya.MathUtil.lerp(burst.minCount, burst.maxCount, this._rand.getFloat()); this._randomSeeds[0] = this._rand.seed; } totalEmitCount += emitCount; } else { break; } } return totalEmitCount; } _advanceTime(elapsedTime, emitTime) { var i; var lastEmissionTime = this._emissionTime; this._emissionTime += elapsedTime; var totalEmitCount = 0; if (this._emissionTime > this.duration) { if (this.looping) { totalEmitCount += this._burst(lastEmissionTime, this._emissionTime); this._emissionTime -= this.duration; this._burstsIndex = 0; totalEmitCount += this._burst(0, this._emissionTime); } else { totalEmitCount = Math.min(this.maxParticles - this.aliveParticleCount, totalEmitCount); for (i = 0; i < totalEmitCount; i++) this.emit(emitTime); this._isPlaying = false; this.stop(); return; } } else { totalEmitCount += this._burst(lastEmissionTime, this._emissionTime); } totalEmitCount = Math.min(this.maxParticles - this.aliveParticleCount, totalEmitCount); for (i = 0; i < totalEmitCount; i++) this.emit(emitTime); var emissionRate = this.emission.emissionRate; if (emissionRate > 0) { var minEmissionTime = 1 / emissionRate; this._frameRateTime += minEmissionTime; this._frameRateTime = this._currentTime - (this._currentTime - this._frameRateTime) % this._maxStartLifetime; while (this._frameRateTime <= emitTime) { if (this.emit(this._frameRateTime)) this._frameRateTime += minEmissionTime; else break; } this._frameRateTime = Math.floor(emitTime / minEmissionTime) * minEmissionTime; } } _initBufferDatas() { if (this._vertexBuffer) { this._vertexBuffer.destroy(); this._indexBuffer.destroy(); var memorySize = this._vertexBuffer._byteLength + this._indexBuffer.indexCount * 2; Laya.Resource._addMemory(-memorySize, -memorySize); } var gl = Laya.LayaGL.instance; var render = this._ownerRender; var renderMode = render.renderMode; if (renderMode !== -1 && this.maxParticles > 0) { var indices, i, j, m, indexOffset, perPartOffset, vertexDeclaration; var vbMemorySize = 0, memorySize = 0; var mesh = render.mesh; if (renderMode === 4) { if (mesh) { vertexDeclaration = VertexShurikenParticleMesh.vertexDeclaration; this._floatCountPerVertex = vertexDeclaration.vertexStride / 4; this._startLifeTimeIndex = 12; this._timeIndex = 16; this._vertexStride = mesh._vertexCount; var totalVertexCount = this._bufferMaxParticles * this._vertexStride; var vbCount = Math.floor(totalVertexCount / 65535) + 1; var lastVBVertexCount = totalVertexCount % 65535; if (vbCount > 1) { throw new Error("ShurikenParticleSystem:the maxParticleCount multiply mesh vertexCount is large than 65535."); } vbMemorySize = vertexDeclaration.vertexStride * lastVBVertexCount; this._vertexBuffer = new VertexBuffer3D(vbMemorySize, gl.DYNAMIC_DRAW); this._vertexBuffer.vertexDeclaration = vertexDeclaration; this._vertices = new Float32Array(this._floatCountPerVertex * lastVBVertexCount); this._indexStride = mesh._indexBuffer.indexCount; var indexDatas = mesh._indexBuffer.getData(); var indexCount = this._bufferMaxParticles * this._indexStride; this._indexBuffer = new IndexBuffer3D(exports.IndexFormat.UInt16, indexCount, gl.STATIC_DRAW); indices = new Uint16Array(indexCount); memorySize = vbMemorySize + indexCount * 2; indexOffset = 0; for (i = 0; i < this._bufferMaxParticles; i++) { var indexValueOffset = i * this._vertexStride; for (j = 0, m = indexDatas.length; j < m; j++) indices[indexOffset++] = indexValueOffset + indexDatas[j]; } this._indexBuffer.setData(indices); this._bufferState.bind(); this._bufferState.applyVertexBuffer(this._vertexBuffer); this._bufferState.applyIndexBuffer(this._indexBuffer); this._bufferState.unBind(); } } else { vertexDeclaration = VertexShurikenParticleBillboard.vertexDeclaration; this._floatCountPerVertex = vertexDeclaration.vertexStride / 4; this._startLifeTimeIndex = 7; this._timeIndex = 11; this._vertexStride = 4; vbMemorySize = vertexDeclaration.vertexStride * this._bufferMaxParticles * this._vertexStride; this._vertexBuffer = new VertexBuffer3D(vbMemorySize, gl.DYNAMIC_DRAW); this._vertexBuffer.vertexDeclaration = vertexDeclaration; this._vertices = new Float32Array(this._floatCountPerVertex * this._bufferMaxParticles * this._vertexStride); for (i = 0; i < this._bufferMaxParticles; i++) { perPartOffset = i * this._floatCountPerVertex * this._vertexStride; this._vertices[perPartOffset] = -0.5; this._vertices[perPartOffset + 1] = -0.5; this._vertices[perPartOffset + 2] = 0; this._vertices[perPartOffset + 3] = 1; perPartOffset += this._floatCountPerVertex; this._vertices[perPartOffset] = 0.5; this._vertices[perPartOffset + 1] = -0.5; this._vertices[perPartOffset + 2] = 1; this._vertices[perPartOffset + 3] = 1; perPartOffset += this._floatCountPerVertex; this._vertices[perPartOffset] = 0.5; this._vertices[perPartOffset + 1] = 0.5; this._vertices[perPartOffset + 2] = 1; this._vertices[perPartOffset + 3] = 0; perPartOffset += this._floatCountPerVertex; this._vertices[perPartOffset] = -0.5; this._vertices[perPartOffset + 1] = 0.5; this._vertices[perPartOffset + 2] = 0; this._vertices[perPartOffset + 3] = 0; } this._indexStride = 6; this._indexBuffer = new IndexBuffer3D(exports.IndexFormat.UInt16, this._bufferMaxParticles * 6, gl.STATIC_DRAW); indices = new Uint16Array(this._bufferMaxParticles * 6); for (i = 0; i < this._bufferMaxParticles; i++) { indexOffset = i * 6; var firstVertex = i * this._vertexStride, secondVertex = firstVertex + 2; indices[indexOffset++] = firstVertex; indices[indexOffset++] = secondVertex; indices[indexOffset++] = firstVertex + 1; indices[indexOffset++] = firstVertex; indices[indexOffset++] = firstVertex + 3; indices[indexOffset++] = secondVertex; } this._indexBuffer.setData(indices); memorySize = vbMemorySize + this._bufferMaxParticles * 6 * 2; this._bufferState.bind(); this._bufferState.applyVertexBuffer(this._vertexBuffer); this._bufferState.applyIndexBuffer(this._indexBuffer); this._bufferState.unBind(); } Laya.Resource._addMemory(memorySize, memorySize); } } destroy() { super.destroy(); var memorySize = this._vertexBuffer._byteLength + this._indexBuffer.indexCount * 2; Laya.Resource._addMemory(-memorySize, -memorySize); this._bufferState.destroy(); this._vertexBuffer.destroy(); this._indexBuffer.destroy(); this._emission.destroy(); this._bufferState = null; this._vertexBuffer = null; this._indexBuffer = null; this._owner = null; this._vertices = null; this._indexBuffer = null; this._emission = null; this._shape = null; this.startLifeTimeGradient = null; this.startLifeTimeGradientMin = null; this.startLifeTimeGradientMax = null; this.startSizeConstantSeparate = null; this.startSizeConstantMinSeparate = null; this.startSizeConstantMaxSeparate = null; this.startRotationConstantSeparate = null; this.startRotationConstantMinSeparate = null; this.startRotationConstantMaxSeparate = null; this.startColorConstant = null; this.startColorConstantMin = null; this.startColorConstantMax = null; this._velocityOverLifetime = null; this._colorOverLifetime = null; this._sizeOverLifetime = null; this._rotationOverLifetime = null; this._textureSheetAnimation = null; } emit(time) { var position = ShurikenParticleSystem._tempPosition; var direction = ShurikenParticleSystem._tempDirection; if (this._shape && this._shape.enable) { if (this.autoRandomSeed) this._shape.generatePositionAndDirection(position, direction); else this._shape.generatePositionAndDirection(position, direction, this._rand, this._randomSeeds); } else { position.x = position.y = position.z = 0; direction.x = direction.y = 0; direction.z = 1; } return this.addParticle(position, direction, time); } addParticle(position, direction, time) { Vector3.normalize(direction, direction); var nextFreeParticle = this._firstFreeElement + 1; if (nextFreeParticle >= this._bufferMaxParticles) nextFreeParticle = 0; if (nextFreeParticle === this._firstRetiredElement) return false; var transform = this._owner.transform; ShurikenParticleData.create(this, this._ownerRender, transform); var particleAge = this._currentTime - time; if (particleAge >= ShurikenParticleData.startLifeTime) return true; var pos, rot; if (this.simulationSpace == 0) { pos = transform.position; rot = transform.rotation; } var startSpeed; switch (this.startSpeedType) { case 0: startSpeed = this.startSpeedConstant; break; case 2: if (this.autoRandomSeed) { startSpeed = Laya.MathUtil.lerp(this.startSpeedConstantMin, this.startSpeedConstantMax, Math.random()); } else { this._rand.seed = this._randomSeeds[8]; startSpeed = Laya.MathUtil.lerp(this.startSpeedConstantMin, this.startSpeedConstantMax, this._rand.getFloat()); this._randomSeeds[8] = this._rand.seed; } break; } var randomVelocityX, randomVelocityY, randomVelocityZ, randomColor, randomSize, randomRotation, randomTextureAnimation; var needRandomVelocity = this._velocityOverLifetime && this._velocityOverLifetime.enable; if (needRandomVelocity) { var velocityType = this._velocityOverLifetime.velocity.type; if (velocityType === 2 || velocityType === 3) { if (this.autoRandomSeed) { randomVelocityX = Math.random(); randomVelocityY = Math.random(); randomVelocityZ = Math.random(); } else { this._rand.seed = this._randomSeeds[9]; randomVelocityX = this._rand.getFloat(); randomVelocityY = this._rand.getFloat(); randomVelocityZ = this._rand.getFloat(); this._randomSeeds[9] = this._rand.seed; } } else { needRandomVelocity = false; } } else { needRandomVelocity = false; } var needRandomColor = this._colorOverLifetime && this._colorOverLifetime.enable; if (needRandomColor) { var colorType = this._colorOverLifetime.color.type; if (colorType === 3) { if (this.autoRandomSeed) { randomColor = Math.random(); } else { this._rand.seed = this._randomSeeds[10]; randomColor = this._rand.getFloat(); this._randomSeeds[10] = this._rand.seed; } } else { needRandomColor = false; } } else { needRandomColor = false; } var needRandomSize = this._sizeOverLifetime && this._sizeOverLifetime.enable; if (needRandomSize) { var sizeType = this._sizeOverLifetime.size.type; if (sizeType === 3) { if (this.autoRandomSeed) { randomSize = Math.random(); } else { this._rand.seed = this._randomSeeds[11]; randomSize = this._rand.getFloat(); this._randomSeeds[11] = this._rand.seed; } } else { needRandomSize = false; } } else { needRandomSize = false; } var needRandomRotation = this._rotationOverLifetime && this._rotationOverLifetime.enable; if (needRandomRotation) { var rotationType = this._rotationOverLifetime.angularVelocity.type; if (rotationType === 2 || rotationType === 3) { if (this.autoRandomSeed) { randomRotation = Math.random(); } else { this._rand.seed = this._randomSeeds[12]; randomRotation = this._rand.getFloat(); this._randomSeeds[12] = this._rand.seed; } } else { needRandomRotation = false; } } else { needRandomRotation = false; } var needRandomTextureAnimation = this._textureSheetAnimation && this._textureSheetAnimation.enable; if (needRandomTextureAnimation) { var textureAnimationType = this._textureSheetAnimation.frame.type; if (textureAnimationType === 3) { if (this.autoRandomSeed) { randomTextureAnimation = Math.random(); } else { this._rand.seed = this._randomSeeds[15]; randomTextureAnimation = this._rand.getFloat(); this._randomSeeds[15] = this._rand.seed; } } else { needRandomTextureAnimation = false; } } else { needRandomTextureAnimation = false; } var startIndex = this._firstFreeElement * this._floatCountPerVertex * this._vertexStride; var subU = ShurikenParticleData.startUVInfo[0]; var subV = ShurikenParticleData.startUVInfo[1]; var startU = ShurikenParticleData.startUVInfo[2]; var startV = ShurikenParticleData.startUVInfo[3]; var meshVertices, meshVertexStride, meshPosOffset, meshCorOffset, meshUVOffset, meshVertexIndex; var render = this._ownerRender; if (render.renderMode === 4) { var meshVB = render.mesh._vertexBuffer; meshVertices = meshVB.getFloat32Data(); var meshVertexDeclaration = meshVB.vertexDeclaration; meshPosOffset = meshVertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_POSITION0)._offset / 4; var colorElement = meshVertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_COLOR0); meshCorOffset = colorElement ? colorElement._offset / 4 : -1; var uvElement = meshVertexDeclaration.getVertexElementByUsage(VertexMesh.MESH_TEXTURECOORDINATE0); meshUVOffset = uvElement ? uvElement._offset / 4 : -1; meshVertexStride = meshVertexDeclaration.vertexStride / 4; meshVertexIndex = 0; } else { this._vertices[startIndex + 2] = startU; this._vertices[startIndex + 3] = startV + subV; var secondOffset = startIndex + this._floatCountPerVertex; this._vertices[secondOffset + 2] = startU + subU; this._vertices[secondOffset + 3] = startV + subV; var thirdOffset = secondOffset + this._floatCountPerVertex; this._vertices[thirdOffset + 2] = startU + subU; this._vertices[thirdOffset + 3] = startV; var fourthOffset = thirdOffset + this._floatCountPerVertex; this._vertices[fourthOffset + 2] = startU; this._vertices[fourthOffset + 3] = startV; } for (var i = startIndex, n = startIndex + this._floatCountPerVertex * this._vertexStride; i < n; i += this._floatCountPerVertex) { var offset; if (render.renderMode === 4) { offset = i; var vertexOffset = meshVertexStride * (meshVertexIndex++); var meshOffset = vertexOffset + meshPosOffset; this._vertices[offset++] = meshVertices[meshOffset++]; this._vertices[offset++] = meshVertices[meshOffset++]; this._vertices[offset++] = meshVertices[meshOffset]; if (meshCorOffset === -1) { this._vertices[offset++] = 1.0; this._vertices[offset++] = 1.0; this._vertices[offset++] = 1.0; this._vertices[offset++] = 1.0; } else { meshOffset = vertexOffset + meshCorOffset; this._vertices[offset++] = meshVertices[meshOffset++]; this._vertices[offset++] = meshVertices[meshOffset++]; this._vertices[offset++] = meshVertices[meshOffset++]; this._vertices[offset++] = meshVertices[meshOffset]; } if (meshUVOffset === -1) { this._vertices[offset++] = 0.0; this._vertices[offset++] = 0.0; } else { meshOffset = vertexOffset + meshUVOffset; this._vertices[offset++] = startU + meshVertices[meshOffset++] * subU; this._vertices[offset++] = startV + meshVertices[meshOffset] * subV; } } else { offset = i + 4; } this._vertices[offset++] = position.x; this._vertices[offset++] = position.y; this._vertices[offset++] = position.z; this._vertices[offset++] = ShurikenParticleData.startLifeTime; this._vertices[offset++] = direction.x; this._vertices[offset++] = direction.y; this._vertices[offset++] = direction.z; this._vertices[offset++] = time; this._vertices[offset++] = ShurikenParticleData.startColor.x; this._vertices[offset++] = ShurikenParticleData.startColor.y; this._vertices[offset++] = ShurikenParticleData.startColor.z; this._vertices[offset++] = ShurikenParticleData.startColor.w; this._vertices[offset++] = ShurikenParticleData.startSize[0]; this._vertices[offset++] = ShurikenParticleData.startSize[1]; this._vertices[offset++] = ShurikenParticleData.startSize[2]; this._vertices[offset++] = ShurikenParticleData.startRotation[0]; this._vertices[offset++] = ShurikenParticleData.startRotation[1]; this._vertices[offset++] = ShurikenParticleData.startRotation[2]; this._vertices[offset++] = startSpeed; needRandomColor && (this._vertices[offset + 1] = randomColor); needRandomSize && (this._vertices[offset + 2] = randomSize); needRandomRotation && (this._vertices[offset + 3] = randomRotation); needRandomTextureAnimation && (this._vertices[offset + 4] = randomTextureAnimation); if (needRandomVelocity) { this._vertices[offset + 5] = randomVelocityX; this._vertices[offset + 6] = randomVelocityY; this._vertices[offset + 7] = randomVelocityZ; } switch (this.simulationSpace) { case 0: offset += 8; this._vertices[offset++] = pos.x; this._vertices[offset++] = pos.y; this._vertices[offset++] = pos.z; this._vertices[offset++] = rot.x; this._vertices[offset++] = rot.y; this._vertices[offset++] = rot.z; this._vertices[offset++] = rot.w; break; case 1: break; default: throw new Error("ShurikenParticleMaterial: SimulationSpace value is invalid."); } } this._firstFreeElement = nextFreeParticle; return true; } addNewParticlesToVertexBuffer() { var start; var byteStride = this._vertexStride * this._floatCountPerVertex * 4; if (this._firstNewElement < this._firstFreeElement) { start = this._firstNewElement * byteStride; this._vertexBuffer.setData(this._vertices.buffer, start, start, (this._firstFreeElement - this._firstNewElement) * byteStride); } else { start = this._firstNewElement * byteStride; this._vertexBuffer.setData(this._vertices.buffer, start, start, (this._bufferMaxParticles - this._firstNewElement) * byteStride); if (this._firstFreeElement > 0) { this._vertexBuffer.setData(this._vertices.buffer, 0, 0, this._firstFreeElement * byteStride); } } this._firstNewElement = this._firstFreeElement; } _getType() { return ShurikenParticleSystem._type; } _prepareRender(state) { this._updateEmission(); if (this._firstNewElement != this._firstFreeElement) this.addNewParticlesToVertexBuffer(); this._drawCounter++; if (this._firstActiveElement != this._firstFreeElement) return true; else return false; } _render(state) { this._bufferState.bind(); var indexCount; var gl = Laya.LayaGL.instance; if (this._firstActiveElement < this._firstFreeElement) { indexCount = (this._firstFreeElement - this._firstActiveElement) * this._indexStride; gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, 2 * this._firstActiveElement * this._indexStride); Laya.Stat.trianglesFaces += indexCount / 3; Laya.Stat.renderBatches++; } else { indexCount = (this._bufferMaxParticles - this._firstActiveElement) * this._indexStride; gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, 2 * this._firstActiveElement * this._indexStride); Laya.Stat.trianglesFaces += indexCount / 3; Laya.Stat.renderBatches++; if (this._firstFreeElement > 0) { indexCount = this._firstFreeElement * this._indexStride; gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, 0); Laya.Stat.trianglesFaces += indexCount / 3; Laya.Stat.renderBatches++; } } } play() { this._burstsIndex = 0; this._isEmitting = true; this._isPlaying = true; this._isPaused = false; this._emissionTime = 0; this._totalDelayTime = 0; if (!this.autoRandomSeed) { for (var i = 0, n = this._randomSeeds.length; i < n; i++) this._randomSeeds[i] = this.randomSeed[0] + ShurikenParticleSystem._RANDOMOFFSET[i]; } switch (this.startDelayType) { case 0: this._playStartDelay = this.startDelay; break; case 1: if (this.autoRandomSeed) { this._playStartDelay = Laya.MathUtil.lerp(this.startDelayMin, this.startDelayMax, Math.random()); } else { this._rand.seed = this._randomSeeds[2]; this._playStartDelay = Laya.MathUtil.lerp(this.startDelayMin, this.startDelayMax, this._rand.getFloat()); this._randomSeeds[2] = this._rand.seed; } break; default: throw new Error("Utils3D: startDelayType is invalid."); } this._frameRateTime = this._currentTime + this._playStartDelay; this._startUpdateLoopCount = Laya.Stat.loopCount; } pause() { this._isPaused = true; } simulate(time, restart = true) { this._simulateUpdate = true; if (restart) { this._updateParticlesSimulationRestart(time); } else { this._isPaused = false; this._updateParticles(time); } this.pause(); } stop() { this._burstsIndex = 0; this._isEmitting = false; this._emissionTime = 0; } cloneTo(destObject) { var dest = destObject; dest.duration = this.duration; dest.looping = this.looping; dest.prewarm = this.prewarm; dest.startDelayType = this.startDelayType; dest.startDelay = this.startDelay; dest.startDelayMin = this.startDelayMin; dest.startDelayMax = this.startDelayMax; dest._maxStartLifetime = this._maxStartLifetime; dest.startLifetimeType = this.startLifetimeType; dest.startLifetimeConstant = this.startLifetimeConstant; this.startLifeTimeGradient.cloneTo(dest.startLifeTimeGradient); dest.startLifetimeConstantMin = this.startLifetimeConstantMin; dest.startLifetimeConstantMax = this.startLifetimeConstantMax; this.startLifeTimeGradientMin.cloneTo(dest.startLifeTimeGradientMin); this.startLifeTimeGradientMax.cloneTo(dest.startLifeTimeGradientMax); dest.startSpeedType = this.startSpeedType; dest.startSpeedConstant = this.startSpeedConstant; dest.startSpeedConstantMin = this.startSpeedConstantMin; dest.startSpeedConstantMax = this.startSpeedConstantMax; dest.threeDStartSize = this.threeDStartSize; dest.startSizeType = this.startSizeType; dest.startSizeConstant = this.startSizeConstant; this.startSizeConstantSeparate.cloneTo(dest.startSizeConstantSeparate); dest.startSizeConstantMin = this.startSizeConstantMin; dest.startSizeConstantMax = this.startSizeConstantMax; this.startSizeConstantMinSeparate.cloneTo(dest.startSizeConstantMinSeparate); this.startSizeConstantMaxSeparate.cloneTo(dest.startSizeConstantMaxSeparate); dest.threeDStartRotation = this.threeDStartRotation; dest.startRotationType = this.startRotationType; dest.startRotationConstant = this.startRotationConstant; this.startRotationConstantSeparate.cloneTo(dest.startRotationConstantSeparate); dest.startRotationConstantMin = this.startRotationConstantMin; dest.startRotationConstantMax = this.startRotationConstantMax; this.startRotationConstantMinSeparate.cloneTo(dest.startRotationConstantMinSeparate); this.startRotationConstantMaxSeparate.cloneTo(dest.startRotationConstantMaxSeparate); dest.randomizeRotationDirection = this.randomizeRotationDirection; dest.startColorType = this.startColorType; this.startColorConstant.cloneTo(dest.startColorConstant); this.startColorConstantMin.cloneTo(dest.startColorConstantMin); this.startColorConstantMax.cloneTo(dest.startColorConstantMax); dest.gravityModifier = this.gravityModifier; dest.simulationSpace = this.simulationSpace; dest.scaleMode = this.scaleMode; dest.playOnAwake = this.playOnAwake; dest.autoRandomSeed = this.autoRandomSeed; dest.randomSeed[0] = this.randomSeed[0]; dest.maxParticles = this.maxParticles; (this._emission) && (dest._emission = this._emission.clone()); (this.shape) && (dest.shape = this.shape.clone()); (this.velocityOverLifetime) && (dest.velocityOverLifetime = this.velocityOverLifetime.clone()); (this.colorOverLifetime) && (dest.colorOverLifetime = this.colorOverLifetime.clone()); (this.sizeOverLifetime) && (dest.sizeOverLifetime = this.sizeOverLifetime.clone()); (this.rotationOverLifetime) && (dest.rotationOverLifetime = this.rotationOverLifetime.clone()); (this.textureSheetAnimation) && (dest.textureSheetAnimation = this.textureSheetAnimation.clone()); dest.isPerformanceMode = this.isPerformanceMode; dest._isEmitting = this._isEmitting; dest._isPlaying = this._isPlaying; dest._isPaused = this._isPaused; dest._playStartDelay = this._playStartDelay; dest._frameRateTime = this._frameRateTime; dest._emissionTime = this._emissionTime; dest._totalDelayTime = this._totalDelayTime; dest._burstsIndex = this._burstsIndex; } clone() { var dest = new ShurikenParticleSystem(null); this.cloneTo(dest); return dest; } } ShurikenParticleSystem._RANDOMOFFSET = new Uint32Array([0x23571a3e, 0xc34f56fe, 0x13371337, 0x12460f3b, 0x6aed452e, 0xdec4aea1, 0x96aa4de3, 0x8d2c8431, 0xf3857f6f, 0xe0fbd834, 0x13740583, 0x591bc05c, 0x40eb95e4, 0xbc524e5f, 0xaf502044, 0xa614b381, 0x1034e524, 0xfc524e5f]); ShurikenParticleSystem.halfKSqrtOf2 = 1.42 * 0.5; ShurikenParticleSystem._maxElapsedTime = 1.0 / 3.0; ShurikenParticleSystem._tempVector30 = new Vector3(); ShurikenParticleSystem._tempVector31 = new Vector3(); ShurikenParticleSystem._tempVector32 = new Vector3(); ShurikenParticleSystem._tempVector33 = new Vector3(); ShurikenParticleSystem._tempVector34 = new Vector3(); ShurikenParticleSystem._tempVector35 = new Vector3(); ShurikenParticleSystem._tempVector36 = new Vector3(); ShurikenParticleSystem._tempVector37 = new Vector3(); ShurikenParticleSystem._tempVector38 = new Vector3(); ShurikenParticleSystem._tempVector39 = new Vector3(); ShurikenParticleSystem._tempPosition = new Vector3(); ShurikenParticleSystem._tempDirection = new Vector3(); ShurikenParticleSystem._type = GeometryElement._typeCounter++; class ShuriKenParticle3D extends RenderableSprite3D { constructor() { super(null); this._render = new ShurikenParticleRenderer(this); this._particleSystem = new ShurikenParticleSystem(this); var elements = this._render._renderElements; var element = elements[0] = new RenderElement(); element.setTransform(this._transform); element.render = this._render; element.setGeometry(this._particleSystem); element.material = ShurikenParticleMaterial.defaultMaterial; } static __init__() { ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_BILLBOARD = Shader3D.getDefineByName("SPHERHBILLBOARD"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_STRETCHEDBILLBOARD = Shader3D.getDefineByName("STRETCHEDBILLBOARD"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_HORIZONTALBILLBOARD = Shader3D.getDefineByName("HORIZONTALBILLBOARD"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_VERTICALBILLBOARD = Shader3D.getDefineByName("VERTICALBILLBOARD"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_COLOROVERLIFETIME = Shader3D.getDefineByName("COLOROVERLIFETIME"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RANDOMCOLOROVERLIFETIME = Shader3D.getDefineByName("RANDOMCOLOROVERLIFETIME"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMECONSTANT = Shader3D.getDefineByName("VELOCITYOVERLIFETIMECONSTANT"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMECURVE = Shader3D.getDefineByName("VELOCITYOVERLIFETIMECURVE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMERANDOMCONSTANT = Shader3D.getDefineByName("VELOCITYOVERLIFETIMERANDOMCONSTANT"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_VELOCITYOVERLIFETIMERANDOMCURVE = Shader3D.getDefineByName("VELOCITYOVERLIFETIMERANDOMCURVE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_TEXTURESHEETANIMATIONCURVE = Shader3D.getDefineByName("TEXTURESHEETANIMATIONCURVE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_TEXTURESHEETANIMATIONRANDOMCURVE = Shader3D.getDefineByName("TEXTURESHEETANIMATIONRANDOMCURVE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIME = Shader3D.getDefineByName("ROTATIONOVERLIFETIME"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMESEPERATE = Shader3D.getDefineByName("ROTATIONOVERLIFETIMESEPERATE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMECONSTANT = Shader3D.getDefineByName("ROTATIONOVERLIFETIMECONSTANT"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMECURVE = Shader3D.getDefineByName("ROTATIONOVERLIFETIMECURVE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMERANDOMCONSTANTS = Shader3D.getDefineByName("ROTATIONOVERLIFETIMERANDOMCONSTANTS"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_ROTATIONOVERLIFETIMERANDOMCURVES = Shader3D.getDefineByName("ROTATIONOVERLIFETIMERANDOMCURVES"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMECURVE = Shader3D.getDefineByName("SIZEOVERLIFETIMECURVE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMECURVESEPERATE = Shader3D.getDefineByName("SIZEOVERLIFETIMECURVESEPERATE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMERANDOMCURVES = Shader3D.getDefineByName("SIZEOVERLIFETIMERANDOMCURVES"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SIZEOVERLIFETIMERANDOMCURVESSEPERATE = Shader3D.getDefineByName("SIZEOVERLIFETIMERANDOMCURVESSEPERATE"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_RENDERMODE_MESH = Shader3D.getDefineByName("RENDERMODE_MESH"); ShuriKenParticle3DShaderDeclaration.SHADERDEFINE_SHAPE = Shader3D.getDefineByName("SHAPE"); } get particleSystem() { return this._particleSystem; } get particleRenderer() { return this._render; } _parseModule(module, moduleData) { for (var t in moduleData) { switch (t) { case "bases": var bases = moduleData.bases; for (var k in bases) module[k] = bases[k]; break; case "vector2s": var vector2s = moduleData.vector2s; for (var k in vector2s) { var vec2 = module[k]; var vec2Data = vector2s[k]; vec2.setValue(vec2Data[0], vec2Data[1]); module[k] = vec2; } break; case "vector3s": var vector3s = moduleData.vector3s; for (var k in vector3s) { var vec3 = module[k]; var vec3Data = vector3s[k]; vec3.setValue(vec3Data[0], vec3Data[1], vec3Data[2]); module[k] = vec3; } break; case "vector4s": var vector4s = moduleData.vector4s; for (var k in vector4s) { var vec4 = module[k]; var vec4Data = vector4s[k]; vec4.setValue(vec4Data[0], vec4Data[1], vec4Data[2], vec4Data[3]); module[k] = vec4; } break; case "gradientDataNumbers": var gradientDataNumbers = moduleData.gradientDataNumbers; for (var k in gradientDataNumbers) { var gradientNumber = module[k]; var gradientNumberData = moduleData[k]; for (var i = 0, n = gradientNumberData.length; i < n; i++) { var valueData = gradientNumberData[i]; gradientNumber.add(valueData.key, valueData.value); } module[k] = gradientNumber; } break; case "resources": var resources = moduleData.resources; for (var k in resources) module[k] = Laya.Loader.getRes(resources[k]); break; case "bursts": var burstsData = moduleData.bursts; for (var i = 0, n = burstsData.length; i < n; i++) { var brust = burstsData[i]; module.addBurst(new Burst(brust.time, brust.min, brust.max)); } break; case "randomSeed": module.randomSeed[0] = moduleData.randomSeed; break; case "shapeType": case "type": case "color": case "size": case "frame": case "startFrame": case "angularVelocity": case "velocity": break; default: throw "ShurikenParticle3D:unknown type."; } } } _parse(data, spriteMap) { super._parse(data, spriteMap); if (data.main) { var particleSystem = this.particleSystem; var particleRender = this.particleRenderer; this._parseModule(particleRender, data.renderer); this._parseModule(particleSystem, data.main); this._parseModule(particleSystem.emission, data.emission); var shapeData = data.shape; if (shapeData) { var shape; switch (shapeData.shapeType) { case 0: shape = new SphereShape(); break; case 1: shape = new HemisphereShape(); break; case 2: shape = new ConeShape(); break; case 3: shape = new BoxShape(); break; case 7: shape = new CircleShape(); break; default: throw "ShuriKenParticle3D:unknown shape type."; } this._parseModule(shape, shapeData); particleSystem.shape = shape; } var velocityOverLifetimeData = data.velocityOverLifetime; if (velocityOverLifetimeData) { var velocityData = velocityOverLifetimeData.velocity; var velocity; switch (velocityData.type) { case 0: var constantData = velocityData.constant; velocity = GradientVelocity.createByConstant(constantData ? new Vector3(constantData[0], constantData[1], constantData[2]) : new Vector3(0, 0, 0)); break; case 1: velocity = GradientVelocity.createByGradient(this._initParticleVelocity(velocityData.gradientX), this._initParticleVelocity(velocityData.gradientY), this._initParticleVelocity(velocityData.gradientZ)); break; case 2: var constantMinData = velocityData.constantMin; var constantMaxData = velocityData.constantMax; velocity = GradientVelocity.createByRandomTwoConstant(constantMinData ? new Vector3(constantMinData[0], constantMinData[1], constantMinData[2]) : new Vector3(0, 0, 0), constantMaxData ? new Vector3(constantMaxData[0], constantMaxData[1], constantMaxData[2]) : new Vector3(0, 0, 0)); break; case 3: velocity = GradientVelocity.createByRandomTwoGradient(this._initParticleVelocity(velocityData.gradientXMin), this._initParticleVelocity(velocityData.gradientXMax), this._initParticleVelocity(velocityData.gradientYMin), this._initParticleVelocity(velocityData.gradientYMax), this._initParticleVelocity(velocityData.gradientZMin), this._initParticleVelocity(velocityData.gradientZMax)); break; } var velocityOverLifetime = new VelocityOverLifetime(velocity); this._parseModule(velocityOverLifetime, velocityOverLifetimeData); particleSystem.velocityOverLifetime = velocityOverLifetime; } var colorOverLifetimeData = data.colorOverLifetime; if (colorOverLifetimeData) { var colorData = colorOverLifetimeData.color; var color; switch (colorData.type) { case 0: var constColorData = colorData.constant; color = GradientColor.createByConstant(constColorData ? new Vector4(constColorData[0], constColorData[1], constColorData[2], constColorData[3]) : new Vector4(0, 0, 0, 0)); break; case 1: color = GradientColor.createByGradient(this._initParticleColor(colorData.gradient)); break; case 2: var minConstColorData = colorData.constantMin; var maxConstColorData = colorData.constantMax; color = GradientColor.createByRandomTwoConstant(minConstColorData ? new Vector4(minConstColorData[0], minConstColorData[1], minConstColorData[2], minConstColorData[3]) : new Vector4(0, 0, 0, 0), minConstColorData ? new Vector4(maxConstColorData[0], maxConstColorData[1], maxConstColorData[2], maxConstColorData[3]) : new Vector4(0, 0, 0, 0)); break; case 3: color = GradientColor.createByRandomTwoGradient(this._initParticleColor(colorData.gradientMin), this._initParticleColor(colorData.gradientMax)); break; } var colorOverLifetime = new ColorOverLifetime(color); this._parseModule(colorOverLifetime, colorOverLifetimeData); particleSystem.colorOverLifetime = colorOverLifetime; } var sizeOverLifetimeData = data.sizeOverLifetime; if (sizeOverLifetimeData) { var sizeData = sizeOverLifetimeData.size; var size; switch (sizeData.type) { case 0: if (sizeData.separateAxes) { size = GradientSize.createByGradientSeparate(this._initParticleSize(sizeData.gradientX), this._initParticleSize(sizeData.gradientY), this._initParticleSize(sizeData.gradientZ)); } else { size = GradientSize.createByGradient(this._initParticleSize(sizeData.gradient)); } break; case 1: if (sizeData.separateAxes) { var constantMinSeparateData = sizeData.constantMinSeparate; var constantMaxSeparateData = sizeData.constantMaxSeparate; size = GradientSize.createByRandomTwoConstantSeparate(constantMinSeparateData ? new Vector3(constantMinSeparateData[0], constantMinSeparateData[1], constantMinSeparateData[2]) : new Vector3(0, 0, 0), constantMaxSeparateData ? new Vector3(constantMaxSeparateData[0], constantMaxSeparateData[1], constantMaxSeparateData[2]) : new Vector3(0, 0, 0)); } else { size = GradientSize.createByRandomTwoConstant(sizeData.constantMin || 0, sizeData.constantMax || 0); } break; case 2: if (sizeData.separateAxes) { size = GradientSize.createByRandomTwoGradientSeparate(this._initParticleSize(sizeData.gradientXMin), this._initParticleSize(sizeData.gradientYMin), this._initParticleSize(sizeData.gradientZMin), this._initParticleSize(sizeData.gradientXMax), this._initParticleSize(sizeData.gradientYMax), this._initParticleSize(sizeData.gradientZMax)); } else { size = GradientSize.createByRandomTwoGradient(this._initParticleSize(sizeData.gradientMin), this._initParticleSize(sizeData.gradientMax)); } break; } var sizeOverLifetime = new SizeOverLifetime(size); this._parseModule(sizeOverLifetime, sizeOverLifetimeData); particleSystem.sizeOverLifetime = sizeOverLifetime; } var rotationOverLifetimeData = data.rotationOverLifetime; if (rotationOverLifetimeData) { var angularVelocityData = rotationOverLifetimeData.angularVelocity; var angularVelocity; switch (angularVelocityData.type) { case 0: if (angularVelocityData.separateAxes) { var conSep = angularVelocityData.constantSeparate; angularVelocity = GradientAngularVelocity.createByConstantSeparate(conSep ? new Vector3(conSep[0], conSep[1], conSep[2]) : new Vector3(0, 0, Math.PI / 4)); } else { angularVelocity = GradientAngularVelocity.createByConstant(angularVelocityData.constant || Math.PI / 4); } break; case 1: if (angularVelocityData.separateAxes) { angularVelocity = GradientAngularVelocity.createByGradientSeparate(this._initParticleRotation(angularVelocityData.gradientX), this._initParticleRotation(angularVelocityData.gradientY), this._initParticleRotation(angularVelocityData.gradientZ)); } else { angularVelocity = GradientAngularVelocity.createByGradient(this._initParticleRotation(angularVelocityData.gradient)); } break; case 2: if (angularVelocityData.separateAxes) { var minSep = angularVelocityData.constantMinSeparate; var maxSep = angularVelocityData.constantMaxSeparate; angularVelocity = GradientAngularVelocity.createByRandomTwoConstantSeparate(minSep ? new Vector3(minSep[0], minSep[1], minSep[2]) : new Vector3(0, 0, 0), maxSep ? new Vector3(maxSep[0], maxSep[1], maxSep[2]) : new Vector3(0, 0, Math.PI / 4)); } else { angularVelocity = GradientAngularVelocity.createByRandomTwoConstant(angularVelocityData.constantMin || 0, angularVelocityData.constantMax || Math.PI / 4); } break; case 3: if (angularVelocityData.separateAxes) ; else { angularVelocity = GradientAngularVelocity.createByRandomTwoGradient(this._initParticleRotation(angularVelocityData.gradientMin), this._initParticleRotation(angularVelocityData.gradientMax)); } break; } var rotationOverLifetime = new RotationOverLifetime(angularVelocity); this._parseModule(rotationOverLifetime, rotationOverLifetimeData); particleSystem.rotationOverLifetime = rotationOverLifetime; } var textureSheetAnimationData = data.textureSheetAnimation; if (textureSheetAnimationData) { var frameData = textureSheetAnimationData.frame; var frameOverTime; switch (frameData.type) { case 0: frameOverTime = FrameOverTime.createByConstant(frameData.constant); break; case 1: frameOverTime = FrameOverTime.createByOverTime(this._initParticleFrame(frameData.overTime)); break; case 2: frameOverTime = FrameOverTime.createByRandomTwoConstant(frameData.constantMin, frameData.constantMax); break; case 3: frameOverTime = FrameOverTime.createByRandomTwoOverTime(this._initParticleFrame(frameData.overTimeMin), this._initParticleFrame(frameData.overTimeMax)); break; } var startFrameData = textureSheetAnimationData.startFrame; var startFrame; switch (startFrameData.type) { case 0: startFrame = StartFrame.createByConstant(startFrameData.constant); break; case 1: startFrame = StartFrame.createByRandomTwoConstant(startFrameData.constantMin, startFrameData.constantMax); break; } var textureSheetAnimation = new TextureSheetAnimation(frameOverTime, startFrame); this._parseModule(textureSheetAnimation, textureSheetAnimationData); particleSystem.textureSheetAnimation = textureSheetAnimation; } } else { this._parseOld(data); } } _activeHierarchy(activeChangeComponents) { super._activeHierarchy(activeChangeComponents); (this.particleSystem.playOnAwake) && (this.particleSystem.play()); } _inActiveHierarchy(activeChangeComponents) { super._inActiveHierarchy(activeChangeComponents); (this.particleSystem.isAlive) && (this.particleSystem.simulate(0, true)); } _cloneTo(destObject, srcSprite, dstSprite) { var destShuriKenParticle3D = destObject; var destParticleSystem = destShuriKenParticle3D._particleSystem; this._particleSystem.cloneTo(destParticleSystem); var destParticleRender = destShuriKenParticle3D._render; var particleRender = this._render; destParticleRender.sharedMaterials = particleRender.sharedMaterials; destParticleRender.enable = particleRender.enable; destParticleRender.renderMode = particleRender.renderMode; destParticleRender.mesh = particleRender.mesh; destParticleRender.stretchedBillboardCameraSpeedScale = particleRender.stretchedBillboardCameraSpeedScale; destParticleRender.stretchedBillboardSpeedScale = particleRender.stretchedBillboardSpeedScale; destParticleRender.stretchedBillboardLengthScale = particleRender.stretchedBillboardLengthScale; destParticleRender.sortingFudge = particleRender.sortingFudge; super._cloneTo(destObject, srcSprite, dstSprite); } destroy(destroyChild = true) { if (this.destroyed) return; super.destroy(destroyChild); this._particleSystem.destroy(); this._particleSystem = null; } _create() { return new ShuriKenParticle3D(); } _parseOld(data) { const anglelToRad = Math.PI / 180.0; var i, n; var particleRender = this.particleRenderer; var material; var materialData = data.material; (materialData) && (material = Laya.Loader.getRes(materialData.path)); particleRender.sharedMaterial = material; var meshPath = data.meshPath; (meshPath) && (particleRender.mesh = Laya.Loader.getRes(meshPath)); particleRender.renderMode = data.renderMode; particleRender.stretchedBillboardCameraSpeedScale = data.stretchedBillboardCameraSpeedScale; particleRender.stretchedBillboardSpeedScale = data.stretchedBillboardSpeedScale; particleRender.stretchedBillboardLengthScale = data.stretchedBillboardLengthScale; particleRender.sortingFudge = data.sortingFudge ? data.sortingFudge : 0.0; var particleSystem = this.particleSystem; particleSystem.isPerformanceMode = data.isPerformanceMode; particleSystem.duration = data.duration; particleSystem.looping = data.looping; particleSystem.prewarm = data.prewarm; particleSystem.startDelayType = data.startDelayType; particleSystem.startDelay = data.startDelay; particleSystem.startDelayMin = data.startDelayMin; particleSystem.startDelayMax = data.startDelayMax; particleSystem.startLifetimeType = data.startLifetimeType; particleSystem.startLifetimeConstant = data.startLifetimeConstant; particleSystem.startLifeTimeGradient = ShuriKenParticle3D._initStartLife(data.startLifetimeGradient); particleSystem.startLifetimeConstantMin = data.startLifetimeConstantMin; particleSystem.startLifetimeConstantMax = data.startLifetimeConstantMax; particleSystem.startLifeTimeGradientMin = ShuriKenParticle3D._initStartLife(data.startLifetimeGradientMin); particleSystem.startLifeTimeGradientMax = ShuriKenParticle3D._initStartLife(data.startLifetimeGradientMax); particleSystem.startSpeedType = data.startSpeedType; particleSystem.startSpeedConstant = data.startSpeedConstant; particleSystem.startSpeedConstantMin = data.startSpeedConstantMin; particleSystem.startSpeedConstantMax = data.startSpeedConstantMax; particleSystem.threeDStartSize = data.threeDStartSize; particleSystem.startSizeType = data.startSizeType; particleSystem.startSizeConstant = data.startSizeConstant; var startSizeConstantSeparateArray = data.startSizeConstantSeparate; var startSizeConstantSeparateElement = particleSystem.startSizeConstantSeparate; startSizeConstantSeparateElement.x = startSizeConstantSeparateArray[0]; startSizeConstantSeparateElement.y = startSizeConstantSeparateArray[1]; startSizeConstantSeparateElement.z = startSizeConstantSeparateArray[2]; particleSystem.startSizeConstantMin = data.startSizeConstantMin; particleSystem.startSizeConstantMax = data.startSizeConstantMax; var startSizeConstantMinSeparateArray = data.startSizeConstantMinSeparate; var startSizeConstantMinSeparateElement = particleSystem.startSizeConstantMinSeparate; startSizeConstantMinSeparateElement.x = startSizeConstantMinSeparateArray[0]; startSizeConstantMinSeparateElement.y = startSizeConstantMinSeparateArray[1]; startSizeConstantMinSeparateElement.z = startSizeConstantMinSeparateArray[2]; var startSizeConstantMaxSeparateArray = data.startSizeConstantMaxSeparate; var startSizeConstantMaxSeparateElement = particleSystem.startSizeConstantMaxSeparate; startSizeConstantMaxSeparateElement.x = startSizeConstantMaxSeparateArray[0]; startSizeConstantMaxSeparateElement.y = startSizeConstantMaxSeparateArray[1]; startSizeConstantMaxSeparateElement.z = startSizeConstantMaxSeparateArray[2]; particleSystem.threeDStartRotation = data.threeDStartRotation; particleSystem.startRotationType = data.startRotationType; particleSystem.startRotationConstant = data.startRotationConstant * anglelToRad; var startRotationConstantSeparateArray = data.startRotationConstantSeparate; var startRotationConstantSeparateElement = particleSystem.startRotationConstantSeparate; startRotationConstantSeparateElement.x = startRotationConstantSeparateArray[0] * anglelToRad; startRotationConstantSeparateElement.y = startRotationConstantSeparateArray[1] * anglelToRad; startRotationConstantSeparateElement.z = startRotationConstantSeparateArray[2] * anglelToRad; particleSystem.startRotationConstantMin = data.startRotationConstantMin * anglelToRad; particleSystem.startRotationConstantMax = data.startRotationConstantMax * anglelToRad; var startRotationConstantMinSeparateArray = data.startRotationConstantMinSeparate; var startRotationConstantMinSeparateElement = particleSystem.startRotationConstantMinSeparate; startRotationConstantMinSeparateElement.x = startRotationConstantMinSeparateArray[0] * anglelToRad; startRotationConstantMinSeparateElement.y = startRotationConstantMinSeparateArray[1] * anglelToRad; startRotationConstantMinSeparateElement.z = startRotationConstantMinSeparateArray[2] * anglelToRad; var startRotationConstantMaxSeparateArray = data.startRotationConstantMaxSeparate; var startRotationConstantMaxSeparateElement = particleSystem.startRotationConstantMaxSeparate; startRotationConstantMaxSeparateElement.x = startRotationConstantMaxSeparateArray[0] * anglelToRad; startRotationConstantMaxSeparateElement.y = startRotationConstantMaxSeparateArray[1] * anglelToRad; startRotationConstantMaxSeparateElement.z = startRotationConstantMaxSeparateArray[2] * anglelToRad; particleSystem.randomizeRotationDirection = data.randomizeRotationDirection; particleSystem.startColorType = data.startColorType; var startColorConstantArray = data.startColorConstant; var startColorConstantElement = particleSystem.startColorConstant; startColorConstantElement.x = startColorConstantArray[0]; startColorConstantElement.y = startColorConstantArray[1]; startColorConstantElement.z = startColorConstantArray[2]; startColorConstantElement.w = startColorConstantArray[3]; var startColorConstantMinArray = data.startColorConstantMin; var startColorConstantMinElement = particleSystem.startColorConstantMin; startColorConstantMinElement.x = startColorConstantMinArray[0]; startColorConstantMinElement.y = startColorConstantMinArray[1]; startColorConstantMinElement.z = startColorConstantMinArray[2]; startColorConstantMinElement.w = startColorConstantMinArray[3]; var startColorConstantMaxArray = data.startColorConstantMax; var startColorConstantMaxElement = particleSystem.startColorConstantMax; startColorConstantMaxElement.x = startColorConstantMaxArray[0]; startColorConstantMaxElement.y = startColorConstantMaxArray[1]; startColorConstantMaxElement.z = startColorConstantMaxArray[2]; startColorConstantMaxElement.w = startColorConstantMaxArray[3]; particleSystem.gravityModifier = data.gravityModifier; particleSystem.simulationSpace = data.simulationSpace; (data.simulationSpeed !== undefined) && (particleSystem.simulationSpeed = data.simulationSpeed); particleSystem.scaleMode = data.scaleMode; particleSystem.playOnAwake = data.playOnAwake; particleSystem.maxParticles = data.maxParticles; var autoRandomSeed = data.autoRandomSeed; (autoRandomSeed != null) && (particleSystem.autoRandomSeed = autoRandomSeed); var randomSeed = data.randomSeed; (randomSeed != null) && (particleSystem.randomSeed[0] = randomSeed); var emissionData = data.emission; var emission = particleSystem.emission; if (emissionData) { emission.emissionRate = emissionData.emissionRate; var burstsData = emissionData.bursts; if (burstsData) for (i = 0, n = burstsData.length; i < n; i++) { var brust = burstsData[i]; emission.addBurst(new Burst(brust.time, brust.min, brust.max)); } emission.enable = emissionData.enable; } else { emission.enable = false; } var shapeData = data.shape; if (shapeData) { var shape; switch (shapeData.shapeType) { case 0: var sphereShape; shape = sphereShape = new SphereShape(); sphereShape.radius = shapeData.sphereRadius; sphereShape.emitFromShell = shapeData.sphereEmitFromShell; sphereShape.randomDirection = shapeData.sphereRandomDirection; break; case 1: var hemiSphereShape; shape = hemiSphereShape = new HemisphereShape(); hemiSphereShape.radius = shapeData.hemiSphereRadius; hemiSphereShape.emitFromShell = shapeData.hemiSphereEmitFromShell; hemiSphereShape.randomDirection = shapeData.hemiSphereRandomDirection; break; case 2: var coneShape; shape = coneShape = new ConeShape(); coneShape.angle = shapeData.coneAngle * anglelToRad; coneShape.radius = shapeData.coneRadius; coneShape.length = shapeData.coneLength; coneShape.emitType = shapeData.coneEmitType; coneShape.randomDirection = shapeData.coneRandomDirection; break; case 3: var boxShape; shape = boxShape = new BoxShape(); boxShape.x = shapeData.boxX; boxShape.y = shapeData.boxY; boxShape.z = shapeData.boxZ; boxShape.randomDirection = shapeData.boxRandomDirection; break; case 7: var circleShape; shape = circleShape = new CircleShape(); circleShape.radius = shapeData.circleRadius; circleShape.arc = shapeData.circleArc * anglelToRad; circleShape.emitFromEdge = shapeData.circleEmitFromEdge; circleShape.randomDirection = shapeData.circleRandomDirection; break; default: var tempShape; shape = tempShape = new CircleShape(); tempShape.radius = shapeData.circleRadius; tempShape.arc = shapeData.circleArc * anglelToRad; tempShape.emitFromEdge = shapeData.circleEmitFromEdge; tempShape.randomDirection = shapeData.circleRandomDirection; break; } shape.enable = shapeData.enable; particleSystem.shape = shape; } var velocityOverLifetimeData = data.velocityOverLifetime; if (velocityOverLifetimeData) { var velocityData = velocityOverLifetimeData.velocity; var velocity; switch (velocityData.type) { case 0: var constantData = velocityData.constant; velocity = GradientVelocity.createByConstant(new Vector3(constantData[0], constantData[1], constantData[2])); break; case 1: velocity = GradientVelocity.createByGradient(this._initParticleVelocity(velocityData.gradientX), this._initParticleVelocity(velocityData.gradientY), this._initParticleVelocity(velocityData.gradientZ)); break; case 2: var constantMinData = velocityData.constantMin; var constantMaxData = velocityData.constantMax; velocity = GradientVelocity.createByRandomTwoConstant(new Vector3(constantMinData[0], constantMinData[1], constantMinData[2]), new Vector3(constantMaxData[0], constantMaxData[1], constantMaxData[2])); break; case 3: velocity = GradientVelocity.createByRandomTwoGradient(this._initParticleVelocity(velocityData.gradientXMin), this._initParticleVelocity(velocityData.gradientXMax), this._initParticleVelocity(velocityData.gradientYMin), this._initParticleVelocity(velocityData.gradientYMax), this._initParticleVelocity(velocityData.gradientZMin), this._initParticleVelocity(velocityData.gradientZMax)); break; } var velocityOverLifetime = new VelocityOverLifetime(velocity); velocityOverLifetime.space = velocityOverLifetimeData.space; velocityOverLifetime.enable = velocityOverLifetimeData.enable; particleSystem.velocityOverLifetime = velocityOverLifetime; } var colorOverLifetimeData = data.colorOverLifetime; if (colorOverLifetimeData) { var colorData = colorOverLifetimeData.color; var color; switch (colorData.type) { case 0: var constColorData = colorData.constant; color = GradientColor.createByConstant(new Vector4(constColorData[0], constColorData[1], constColorData[2], constColorData[3])); break; case 1: color = GradientColor.createByGradient(this._initParticleColor(colorData.gradient)); break; case 2: var minConstColorData = colorData.constantMin; var maxConstColorData = colorData.constantMax; color = GradientColor.createByRandomTwoConstant(new Vector4(minConstColorData[0], minConstColorData[1], minConstColorData[2], minConstColorData[3]), new Vector4(maxConstColorData[0], maxConstColorData[1], maxConstColorData[2], maxConstColorData[3])); break; case 3: color = GradientColor.createByRandomTwoGradient(this._initParticleColor(colorData.gradientMin), this._initParticleColor(colorData.gradientMax)); break; } var colorOverLifetime = new ColorOverLifetime(color); colorOverLifetime.enable = colorOverLifetimeData.enable; particleSystem.colorOverLifetime = colorOverLifetime; } var sizeOverLifetimeData = data.sizeOverLifetime; if (sizeOverLifetimeData) { var sizeData = sizeOverLifetimeData.size; var size; switch (sizeData.type) { case 0: if (sizeData.separateAxes) { size = GradientSize.createByGradientSeparate(this._initParticleSize(sizeData.gradientX), this._initParticleSize(sizeData.gradientY), this._initParticleSize(sizeData.gradientZ)); } else { size = GradientSize.createByGradient(this._initParticleSize(sizeData.gradient)); } break; case 1: if (sizeData.separateAxes) { var constantMinSeparateData = sizeData.constantMinSeparate; var constantMaxSeparateData = sizeData.constantMaxSeparate; size = GradientSize.createByRandomTwoConstantSeparate(new Vector3(constantMinSeparateData[0], constantMinSeparateData[1], constantMinSeparateData[2]), new Vector3(constantMaxSeparateData[0], constantMaxSeparateData[1], constantMaxSeparateData[2])); } else { size = GradientSize.createByRandomTwoConstant(sizeData.constantMin, sizeData.constantMax); } break; case 2: if (sizeData.separateAxes) { size = GradientSize.createByRandomTwoGradientSeparate(this._initParticleSize(sizeData.gradientXMin), this._initParticleSize(sizeData.gradientYMin), this._initParticleSize(sizeData.gradientZMin), this._initParticleSize(sizeData.gradientXMax), this._initParticleSize(sizeData.gradientYMax), this._initParticleSize(sizeData.gradientZMax)); } else { size = GradientSize.createByRandomTwoGradient(this._initParticleSize(sizeData.gradientMin), this._initParticleSize(sizeData.gradientMax)); } break; } var sizeOverLifetime = new SizeOverLifetime(size); sizeOverLifetime.enable = sizeOverLifetimeData.enable; particleSystem.sizeOverLifetime = sizeOverLifetime; } var rotationOverLifetimeData = data.rotationOverLifetime; if (rotationOverLifetimeData) { var angularVelocityData = rotationOverLifetimeData.angularVelocity; var angularVelocity; switch (angularVelocityData.type) { case 0: if (angularVelocityData.separateAxes) { var conSep = angularVelocityData.constantSeparate; angularVelocity = GradientAngularVelocity.createByConstantSeparate(new Vector3(conSep[0] * anglelToRad, conSep[1] * anglelToRad, conSep[2] * anglelToRad)); } else { angularVelocity = GradientAngularVelocity.createByConstant(angularVelocityData.constant * anglelToRad); } break; case 1: if (angularVelocityData.separateAxes) { angularVelocity = GradientAngularVelocity.createByGradientSeparate(this._initParticleRotation(angularVelocityData.gradientX), this._initParticleRotation(angularVelocityData.gradientY), this._initParticleRotation(angularVelocityData.gradientZ)); } else { angularVelocity = GradientAngularVelocity.createByGradient(this._initParticleRotation(angularVelocityData.gradient)); } break; case 2: if (angularVelocityData.separateAxes) { var minSep = angularVelocityData.constantMinSeparate; var maxSep = angularVelocityData.constantMaxSeparate; angularVelocity = GradientAngularVelocity.createByRandomTwoConstantSeparate(new Vector3(minSep[0] * anglelToRad, minSep[1] * anglelToRad, minSep[2] * anglelToRad), new Vector3(maxSep[0] * anglelToRad, maxSep[1] * anglelToRad, maxSep[2] * anglelToRad)); } else { angularVelocity = GradientAngularVelocity.createByRandomTwoConstant(angularVelocityData.constantMin * anglelToRad, angularVelocityData.constantMax * anglelToRad); } break; case 3: if (angularVelocityData.separateAxes) ; else { angularVelocity = GradientAngularVelocity.createByRandomTwoGradient(this._initParticleRotation(angularVelocityData.gradientMin), this._initParticleRotation(angularVelocityData.gradientMax)); } break; } var rotationOverLifetime = new RotationOverLifetime(angularVelocity); rotationOverLifetime.enable = rotationOverLifetimeData.enable; particleSystem.rotationOverLifetime = rotationOverLifetime; } var textureSheetAnimationData = data.textureSheetAnimation; if (textureSheetAnimationData) { var frameData = textureSheetAnimationData.frame; var frameOverTime; switch (frameData.type) { case 0: frameOverTime = FrameOverTime.createByConstant(frameData.constant); break; case 1: frameOverTime = FrameOverTime.createByOverTime(this._initParticleFrame(frameData.overTime)); break; case 2: frameOverTime = FrameOverTime.createByRandomTwoConstant(frameData.constantMin, frameData.constantMax); break; case 3: frameOverTime = FrameOverTime.createByRandomTwoOverTime(this._initParticleFrame(frameData.overTimeMin), this._initParticleFrame(frameData.overTimeMax)); break; } var startFrameData = textureSheetAnimationData.startFrame; var startFrame; switch (startFrameData.type) { case 0: startFrame = StartFrame.createByConstant(startFrameData.constant); break; case 1: startFrame = StartFrame.createByRandomTwoConstant(startFrameData.constantMin, startFrameData.constantMax); break; } var textureSheetAnimation = new TextureSheetAnimation(frameOverTime, startFrame); textureSheetAnimation.enable = textureSheetAnimationData.enable; var tilesData = textureSheetAnimationData.tiles; textureSheetAnimation.tiles = new Vector2(tilesData[0], tilesData[1]); textureSheetAnimation.type = textureSheetAnimationData.type; textureSheetAnimation.randomRow = textureSheetAnimationData.randomRow; var rowIndex = textureSheetAnimationData.rowIndex; (rowIndex !== undefined) && (textureSheetAnimation.rowIndex = rowIndex); textureSheetAnimation.cycles = textureSheetAnimationData.cycles; particleSystem.textureSheetAnimation = textureSheetAnimation; } } _initParticleColor(gradientColorData) { var gradientColor = new Gradient(4, 4); if (!gradientColorData) { gradientColor.addColorAlpha(0, 1); gradientColor.addColorAlpha(1, 1); gradientColor.addColorRGB(0, new Color(1.0, 1.0, 1.0, 1.0)); gradientColor.addColorRGB(1, new Color(1.0, 1.0, 1.0, 1.0)); } else { var alphasData = gradientColorData.alphas; var i, n; if (!alphasData) { gradientColor.addColorAlpha(0, 1); gradientColor.addColorAlpha(1, 1); } else { for (i = 0, n = alphasData.length; i < n; i++) { if (i == 3 && n > 4) { i = n - 1; console.warn("GradientDataColor warning:alpha data length is large than 4, will ignore the middle data."); } var alphaData = alphasData[i]; gradientColor.addColorAlpha(alphaData.key, alphaData.value); } } var rgbsData = gradientColorData.rgbs; if (!rgbsData) { gradientColor.addColorRGB(0, new Color(1.0, 1.0, 1.0, 1.0)); gradientColor.addColorRGB(1, new Color(1.0, 1.0, 1.0, 1.0)); } else { for (i = 0, n = rgbsData.length; i < n; i++) { if (i == 3 && n > 4) { i = n - 1; console.warn("GradientDataColor warning:rgb data length is large than 4, will ignore the middle data."); } var rgbData = rgbsData[i]; var rgbValue = rgbData.value; gradientColor.addColorRGB(rgbData.key, new Color(rgbValue[0], rgbValue[1], rgbValue[2], 1.0)); } } } return gradientColor; } _initParticleFrame(overTimeFramesData) { var overTimeFrame = new GradientDataInt(); if (overTimeFramesData) { var framesData = overTimeFramesData.frames; for (var i = 0, n = framesData.length; i < n; i++) { var frameData = framesData[i]; overTimeFrame.add(frameData.key, frameData.value); } } else { overTimeFrame.add(0, 0); overTimeFrame.add(1, 1); } return overTimeFrame; } static _initStartLife(gradientData) { var gradient = new GradientDataNumber(); var startLifetimesData = gradientData.startLifetimes; for (var i = 0, n = startLifetimesData.length; i < n; i++) { var valueData = startLifetimesData[i]; gradient.add(valueData.key, valueData.value); } return gradient; } _initParticleVelocity(gradientData) { var gradient = new GradientDataNumber(); var velocitysData = gradientData.velocitys; for (var i = 0, n = velocitysData.length; i < n; i++) { var valueData = velocitysData[i]; gradient.add(valueData.key, valueData.value); } return gradient; } _initParticleSize(gradientSizeData) { var gradientSize = new GradientDataNumber(); if (gradientSizeData) { var sizesData = gradientSizeData.sizes; for (var i = 0, n = sizesData.length; i < n; i++) { var valueData = sizesData[i]; gradientSize.add(valueData.key, valueData.value); } } else { gradientSize.add(0, 0); gradientSize.add(1, 1); } return gradientSize; } _initParticleRotation(gradientData) { var gradient = new GradientDataNumber(); var angularVelocitysData = gradientData.angularVelocitys; for (var i = 0, n = angularVelocitysData.length; i < n; i++) { var valueData = angularVelocitysData[i]; gradient.add(valueData.key, valueData.value / 180.0 * Math.PI); } return gradient; } } class SkinnedMeshSprite3DShaderDeclaration { } class SkinnedMeshRenderer extends MeshRenderer { constructor(owner) { super(owner); this._bones = []; this._skinnedDataLoopMarks = []; this._localBounds = new Bounds(Vector3._ZERO, Vector3._ZERO); this._cacheAnimationNode = []; } get localBounds() { return this._localBounds; } set localBounds(value) { this._localBounds = value; } get rootBone() { return this._cacheRootBone; } set rootBone(value) { if (this._cacheRootBone != value) { if (this._cacheRootBone) this._cacheRootBone.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange); else this._owner.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange); if (value) value.transform.on(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange); else this._owner.transform.on(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange); this._cacheRootBone = value; this._onWorldMatNeedChange(Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDSCALE); } } get bones() { return this._bones; } _computeSkinnedData() { if (this._cacheMesh && this._cacheAvatar || this._cacheMesh && !this._cacheAvatar) { var bindPoses = this._cacheMesh._inverseBindPoses; var pathMarks = this._cacheMesh._skinnedMatrixCaches; for (var i = 0, n = this._cacheMesh.subMeshCount; i < n; i++) { var subMeshBoneIndices = this._cacheMesh.getSubMesh(i)._boneIndicesList; var subData = this._skinnedData[i]; for (var j = 0, m = subMeshBoneIndices.length; j < m; j++) { var boneIndices = subMeshBoneIndices[j]; this._computeSubSkinnedData(bindPoses, boneIndices, subData[j], pathMarks); } } } } _computeSubSkinnedData(bindPoses, boneIndices, data, matrixCaches) { for (var k = 0, q = boneIndices.length; k < q; k++) { var index = boneIndices[k]; if (this._skinnedDataLoopMarks[index] === Laya.Stat.loopCount) { var c = matrixCaches[index]; var preData = this._skinnedData[c.subMeshIndex][c.batchIndex]; var srcIndex = c.batchBoneIndex * 16; var dstIndex = k * 16; for (var d = 0; d < 16; d++) data[dstIndex + d] = preData[srcIndex + d]; } else { if (!this._cacheAvatar) { Utils3D._mulMatrixArray(this._bones[index].transform.worldMatrix.elements, bindPoses[index].elements, 0, data, k * 16); } else { Utils3D._mulMatrixArray(this._cacheAnimationNode[index].transform.getWorldMatrix(), bindPoses[index].elements, 0, data, k * 16); } this._skinnedDataLoopMarks[index] = Laya.Stat.loopCount; } } } _onWorldMatNeedChange(flag) { this._boundsChange = true; if (this._octreeNode) { if (this._cacheAvatar) { if (this._indexInOctreeMotionList === -1) this._octreeNode._octree.addMotionObject(this); } else { flag &= Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDSCALE; if (flag) { if (this._indexInOctreeMotionList === -1) this._octreeNode._octree.addMotionObject(this); } } } } _createRenderElement() { return new RenderElement(); } _onMeshChange(value) { super._onMeshChange(value); this._cacheMesh = value; var subMeshCount = value.subMeshCount; this._skinnedData = []; this._skinnedDataLoopMarks.length = value._inverseBindPoses.length; for (var i = 0; i < subMeshCount; i++) { var subBoneIndices = value.getSubMesh(i)._boneIndicesList; var subCount = subBoneIndices.length; var subData = this._skinnedData[i] = []; for (var j = 0; j < subCount; j++) subData[j] = new Float32Array(subBoneIndices[j].length * 16); } (this._cacheAvatar && value) && (this._getCacheAnimationNodes()); } _setCacheAnimator(animator) { this._cacheAnimator = animator; this._shaderValues.addDefine(SkinnedMeshSprite3DShaderDeclaration.SHADERDEFINE_BONE); this._setRootNode(); } _calculateBoundingBox() { if (!this._cacheAvatar) { if (this._cacheRootBone) this._localBounds._tranform(this._cacheRootBone.transform.worldMatrix, this._bounds); else this._localBounds._tranform(this._owner.transform.worldMatrix, this._bounds); } else { if (this._cacheAnimator && this._rootBone) { var worldMat = SkinnedMeshRenderer._tempMatrix4x4; Utils3D.matrix4x4MultiplyMFM(this._cacheAnimator.owner.transform.worldMatrix, this._cacheRootAnimationNode.transform.getWorldMatrix(), worldMat); this._localBounds._tranform(worldMat, this._bounds); } else { super._calculateBoundingBox(); } } if (Laya.Render.supportWebGLPlusCulling) { var min = this._bounds.getMin(); var max = this._bounds.getMax(); var buffer = FrustumCulling._cullingBuffer; buffer[this._cullingBufferIndex + 1] = min.x; buffer[this._cullingBufferIndex + 2] = min.y; buffer[this._cullingBufferIndex + 3] = min.z; buffer[this._cullingBufferIndex + 4] = max.x; buffer[this._cullingBufferIndex + 5] = max.y; buffer[this._cullingBufferIndex + 6] = max.z; } } _renderUpdate(context, transform) { if (this._cacheAnimator) { this._computeSkinnedData(); if (!this._cacheAvatar) { this._shaderValues.setMatrix4x4(Sprite3D.WORLDMATRIX, Matrix4x4.DEFAULT); } else { var aniOwnerTrans = this._cacheAnimator.owner._transform; this._shaderValues.setMatrix4x4(Sprite3D.WORLDMATRIX, aniOwnerTrans.worldMatrix); } } else { this._shaderValues.setMatrix4x4(Sprite3D.WORLDMATRIX, transform.worldMatrix); } } _renderUpdateWithCamera(context, transform) { var projectionView = context.projectionViewMatrix; if (this._cacheAnimator) { if (!this._cacheAvatar) { this._shaderValues.setMatrix4x4(Sprite3D.MVPMATRIX, projectionView); } else { var aniOwnerTrans = this._cacheAnimator.owner._transform; Matrix4x4.multiply(projectionView, aniOwnerTrans.worldMatrix, this._projectionViewWorldMatrix); this._shaderValues.setMatrix4x4(Sprite3D.MVPMATRIX, this._projectionViewWorldMatrix); } } else { Matrix4x4.multiply(projectionView, transform.worldMatrix, this._projectionViewWorldMatrix); this._shaderValues.setMatrix4x4(Sprite3D.MVPMATRIX, this._projectionViewWorldMatrix); } } _destroy() { super._destroy(); if (!this._cacheAvatar) { if (this._cacheRootBone) (!this._cacheRootBone.destroyed) && (this._cacheRootBone.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange)); else (this._owner && !this._owner.destroyed) && (this._owner.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange)); } else { if (this._cacheRootAnimationNode) this._cacheRootAnimationNode.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange); } } get bounds() { if (this._boundsChange || this._cacheAvatar) { this._calculateBoundingBox(); this._boundsChange = false; } return this._bounds; } _setRootBone(name) { this._rootBone = name; this._setRootNode(); } _setRootNode() { var rootNode; if (this._cacheAnimator && this._rootBone && this._cacheAvatar) rootNode = this._cacheAnimator._avatarNodeMap[this._rootBone]; else rootNode = null; if (this._cacheRootAnimationNode != rootNode) { this._onWorldMatNeedChange(Transform3D.TRANSFORM_WORLDPOSITION | Transform3D.TRANSFORM_WORLDQUATERNION | Transform3D.TRANSFORM_WORLDSCALE); this._owner.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange); if (this._cacheRootAnimationNode) this._cacheRootAnimationNode.transform.off(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange); (rootNode) && (rootNode.transform.on(Laya.Event.TRANSFORM_CHANGED, this, this._onWorldMatNeedChange)); this._cacheRootAnimationNode = rootNode; } } _getCacheAnimationNodes() { var meshBoneNames = this._cacheMesh._boneNames; var innerBindPoseCount = this._cacheMesh._inverseBindPoses.length; if (!Laya.Render.supportWebGLPlusAnimation) { this._cacheAnimationNode.length = innerBindPoseCount; var nodeMap = this._cacheAnimator._avatarNodeMap; for (var i = 0; i < innerBindPoseCount; i++) { var node = nodeMap[meshBoneNames[i]]; this._cacheAnimationNode[i] = node; } } else { this._cacheAnimationNodeIndices = new Uint16Array(innerBindPoseCount); var nodeMapC = this._cacheAnimator._avatarNodeMap; for (i = 0; i < innerBindPoseCount; i++) { var nodeC = nodeMapC[meshBoneNames[i]]; this._cacheAnimationNodeIndices[i] = nodeC ? nodeC._worldMatrixIndex : 0; } } } _setCacheAvatar(value) { if (this._cacheAvatar !== value) { if (this._cacheMesh) { this._cacheAvatar = value; if (value) { this._shaderValues.addDefine(SkinnedMeshSprite3DShaderDeclaration.SHADERDEFINE_BONE); this._getCacheAnimationNodes(); } } else { this._cacheAvatar = value; } this._setRootNode(); } } _computeSubSkinnedDataNative(worldMatrixs, cacheAnimationNodeIndices, inverseBindPosesBuffer, boneIndices, data) { Laya.LayaGL.instance.computeSubSkinnedData(worldMatrixs, cacheAnimationNodeIndices, inverseBindPosesBuffer, boneIndices, data); } _computeSkinnedDataForNative() { if (this._cacheMesh && this._cacheAvatar || this._cacheMesh && !this._cacheAvatar) { var bindPoses = this._cacheMesh._inverseBindPoses; var pathMarks = this._cacheMesh._skinnedMatrixCaches; for (var i = 0, n = this._cacheMesh.subMeshCount; i < n; i++) { var subMeshBoneIndices = this._cacheMesh.getSubMesh(i)._boneIndicesList; var subData = this._skinnedData[i]; for (var j = 0, m = subMeshBoneIndices.length; j < m; j++) { var boneIndices = subMeshBoneIndices[j]; if (this._cacheAvatar && Laya.Render.supportWebGLPlusAnimation) this._computeSubSkinnedDataNative(this._cacheAnimator._animationNodeWorldMatrixs, this._cacheAnimationNodeIndices, this._cacheMesh._inverseBindPosesBuffer, boneIndices, subData[j]); else this._computeSubSkinnedData(bindPoses, boneIndices, subData[j], pathMarks); } } } } } SkinnedMeshRenderer._tempMatrix4x4 = new Matrix4x4(); class SkinnedMeshSprite3D extends RenderableSprite3D { constructor(mesh = null, name = null) { super(name); this._meshFilter = new MeshFilter(this); this._render = new SkinnedMeshRenderer(this); (mesh) && (this._meshFilter.sharedMesh = mesh); } static __init__() { SkinnedMeshSprite3DShaderDeclaration.SHADERDEFINE_BONE = Shader3D.getDefineByName("BONE"); } get meshFilter() { return this._meshFilter; } get skinnedMeshRenderer() { return this._render; } _parse(data, spriteMap) { super._parse(data, spriteMap); var render = this.skinnedMeshRenderer; var lightmapIndex = data.lightmapIndex; (lightmapIndex != null) && (render.lightmapIndex = lightmapIndex); var lightmapScaleOffsetArray = data.lightmapScaleOffset; (lightmapScaleOffsetArray) && (render.lightmapScaleOffset = new Vector4(lightmapScaleOffsetArray[0], lightmapScaleOffsetArray[1], lightmapScaleOffsetArray[2], lightmapScaleOffsetArray[3])); (data.enableRender != undefined) && (render.enable = data.enableRender); (data.receiveShadows != undefined) && (render.receiveShadow = data.receiveShadows); (data.castShadow != undefined) && (render.castShadow = data.castShadow); var meshPath; meshPath = data.meshPath; if (meshPath) { var mesh = Laya.Loader.getRes(meshPath); (mesh) && (this.meshFilter.sharedMesh = mesh); } var materials = data.materials; if (materials) { var sharedMaterials = render.sharedMaterials; var materialCount = materials.length; sharedMaterials.length = materialCount; for (var i = 0; i < materialCount; i++) { sharedMaterials[i] = Laya.Loader.getRes(materials[i].path); } render.sharedMaterials = sharedMaterials; } var boundBox = data.boundBox; var min = boundBox.min; var max = boundBox.max; render.localBounds.setMin(new Vector3(min[0], min[1], min[2])); render.localBounds.setMax(new Vector3(max[0], max[1], max[2])); if (spriteMap) { var rootBoneData = data.rootBone; render.rootBone = spriteMap[rootBoneData]; var bonesData = data.bones; var n; for (i = 0, n = bonesData.length; i < n; i++) render.bones.push(spriteMap[bonesData[i]]); } else { (data.rootBone) && (render._setRootBone(data.rootBone)); } } _changeHierarchyAnimator(animator) { super._changeHierarchyAnimator(animator); this.skinnedMeshRenderer._setCacheAnimator(animator); } _changeAnimatorAvatar(avatar) { this.skinnedMeshRenderer._setCacheAvatar(avatar); } _cloneTo(destObject, srcRoot, dstRoot) { var meshSprite3D = destObject; meshSprite3D.meshFilter.sharedMesh = this.meshFilter.sharedMesh; var meshRender = this._render; var destMeshRender = meshSprite3D._render; destMeshRender.enable = meshRender.enable; destMeshRender.sharedMaterials = meshRender.sharedMaterials; destMeshRender.castShadow = meshRender.castShadow; var lightmapScaleOffset = meshRender.lightmapScaleOffset; lightmapScaleOffset && (destMeshRender.lightmapScaleOffset = lightmapScaleOffset.clone()); destMeshRender.receiveShadow = meshRender.receiveShadow; destMeshRender.sortingFudge = meshRender.sortingFudge; destMeshRender._rootBone = meshRender._rootBone; var bones = meshRender.bones; var destBones = destMeshRender.bones; var bonesCount = bones.length; destBones.length = bonesCount; var rootBone = meshRender.rootBone; if (rootBone) { var pathes = Utils3D._getHierarchyPath(srcRoot, rootBone, SkinnedMeshSprite3D._tempArray0); if (pathes) destMeshRender.rootBone = Utils3D._getNodeByHierarchyPath(dstRoot, pathes); else destMeshRender.rootBone = rootBone; } for (var i = 0; i < bones.length; i++) { pathes = Utils3D._getHierarchyPath(srcRoot, bones[i], SkinnedMeshSprite3D._tempArray0); if (pathes) destBones[i] = Utils3D._getNodeByHierarchyPath(dstRoot, pathes); else destBones[i] = bones[i]; } var lbb = meshRender.localBounds; (lbb) && (lbb.cloneTo(destMeshRender.localBounds)); super._cloneTo(destObject, srcRoot, dstRoot); } destroy(destroyChild = true) { if (this.destroyed) return; super.destroy(destroyChild); this._meshFilter.destroy(); } _create() { return new SkinnedMeshSprite3D(); } } SkinnedMeshSprite3D._tempArray0 = []; SkinnedMeshSprite3D.BONES = Shader3D.propertyNameToID("u_Bones"); class TrailMaterial extends Material { constructor() { super(); this.setShaderName("Trail"); this._color = new Vector4(1.0, 1.0, 1.0, 1.0); this._shaderValues.setVector(TrailMaterial.TINTCOLOR, new Vector4(1.0, 1.0, 1.0, 1.0)); this.renderMode = TrailMaterial.RENDERMODE_ALPHABLENDED; } static __initDefine__() { TrailMaterial.SHADERDEFINE_MAINTEXTURE = Shader3D.getDefineByName("MAINTEXTURE"); TrailMaterial.SHADERDEFINE_TILINGOFFSET = Shader3D.getDefineByName("TILINGOFFSET"); TrailMaterial.SHADERDEFINE_ADDTIVEFOG = Shader3D.getDefineByName("ADDTIVEFOG"); } get _TintColorR() { return this._color.x; } set _TintColorR(value) { this._color.x = value; this.color = this._color; } get _TintColorG() { return this._color.y; } set _TintColorG(value) { this._color.y = value; this.color = this._color; } get _TintColorB() { return this._color.z; } set _TintColorB(value) { this._color.z = value; this.color = this._color; } get _TintColorA() { return this._color.w; } set _TintColorA(value) { this._color.w = value; this.color = this._color; } get _MainTex_STX() { return this._shaderValues.getVector(TrailMaterial.TILINGOFFSET).x; } set _MainTex_STX(x) { var tilOff = this._shaderValues.getVector(TrailMaterial.TILINGOFFSET); tilOff.x = x; this.tilingOffset = tilOff; } get _MainTex_STY() { return this._shaderValues.getVector(TrailMaterial.TILINGOFFSET).y; } set _MainTex_STY(y) { var tilOff = this._shaderValues.getVector(TrailMaterial.TILINGOFFSET); tilOff.y = y; this.tilingOffset = tilOff; } get _MainTex_STZ() { return this._shaderValues.getVector(TrailMaterial.TILINGOFFSET).z; } set _MainTex_STZ(z) { var tilOff = this._shaderValues.getVector(TrailMaterial.TILINGOFFSET); tilOff.z = z; this.tilingOffset = tilOff; } get _MainTex_STW() { return this._shaderValues.getVector(TrailMaterial.TILINGOFFSET).w; } set _MainTex_STW(w) { var tilOff = this._shaderValues.getVector(TrailMaterial.TILINGOFFSET); tilOff.w = w; this.tilingOffset = tilOff; } set renderMode(value) { switch (value) { case TrailMaterial.RENDERMODE_ADDTIVE: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.alphaTest = false; this.depthWrite = false; this.cull = RenderState.CULL_NONE; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE; this.depthTest = RenderState.DEPTHTEST_LESS; this._shaderValues.addDefine(TrailMaterial.SHADERDEFINE_ADDTIVEFOG); break; case TrailMaterial.RENDERMODE_ALPHABLENDED: this.renderQueue = Material.RENDERQUEUE_TRANSPARENT; this.alphaTest = false; this.depthWrite = false; this.cull = RenderState.CULL_NONE; this.blend = RenderState.BLEND_ENABLE_ALL; this.blendSrc = RenderState.BLENDPARAM_SRC_ALPHA; this.blendDst = RenderState.BLENDPARAM_ONE_MINUS_SRC_ALPHA; this.depthTest = RenderState.DEPTHTEST_LESS; this._shaderValues.removeDefine(TrailMaterial.SHADERDEFINE_ADDTIVEFOG); break; default: throw new Error("TrailMaterial : renderMode value error."); } } get colorR() { return this._TintColorR; } set colorR(value) { this._TintColorR = value; } get colorG() { return this._TintColorG; } set colorG(value) { this._TintColorG = value; } get colorB() { return this._TintColorB; } set colorB(value) { this._TintColorB = value; } get colorA() { return this._TintColorA; } set colorA(value) { this._TintColorA = value; } get color() { return this._shaderValues.getVector(TrailMaterial.TINTCOLOR); } set color(value) { this._shaderValues.setVector(TrailMaterial.TINTCOLOR, value); } get texture() { return this._shaderValues.getTexture(TrailMaterial.MAINTEXTURE); } set texture(value) { if (value) this._shaderValues.addDefine(TrailMaterial.SHADERDEFINE_MAINTEXTURE); else this._shaderValues.removeDefine(TrailMaterial.SHADERDEFINE_MAINTEXTURE); this._shaderValues.setTexture(TrailMaterial.MAINTEXTURE, value); } get tilingOffsetX() { return this._MainTex_STX; } set tilingOffsetX(x) { this._MainTex_STX = x; } get tilingOffsetY() { return this._MainTex_STY; } set tilingOffsetY(y) { this._MainTex_STY = y; } get tilingOffsetZ() { return this._MainTex_STZ; } set tilingOffsetZ(z) { this._MainTex_STZ = z; } get tilingOffsetW() { return this._MainTex_STW; } set tilingOffsetW(w) { this._MainTex_STW = w; } get tilingOffset() { return this._shaderValues.getVector(TrailMaterial.TILINGOFFSET); } set tilingOffset(value) { if (value) { if (value.x != 1 || value.y != 1 || value.z != 0 || value.w != 0) this._shaderValues.addDefine(TrailMaterial.SHADERDEFINE_TILINGOFFSET); else this._shaderValues.removeDefine(TrailMaterial.SHADERDEFINE_TILINGOFFSET); } else { this._shaderValues.removeDefine(TrailMaterial.SHADERDEFINE_TILINGOFFSET); } this._shaderValues.setVector(TrailMaterial.TILINGOFFSET, value); } set depthWrite(value) { this._shaderValues.setBool(TrailMaterial.DEPTH_WRITE, value); } get depthWrite() { return this._shaderValues.getBool(TrailMaterial.DEPTH_WRITE); } set cull(value) { this._shaderValues.setInt(TrailMaterial.CULL, value); } get cull() { return this._shaderValues.getInt(TrailMaterial.CULL); } set blend(value) { this._shaderValues.setInt(TrailMaterial.BLEND, value); } get blend() { return this._shaderValues.getInt(TrailMaterial.BLEND); } set blendSrc(value) { this._shaderValues.setInt(TrailMaterial.BLEND_SRC, value); } get blendSrc() { return this._shaderValues.getInt(TrailMaterial.BLEND_SRC); } set blendDst(value) { this._shaderValues.setInt(TrailMaterial.BLEND_DST, value); } get blendDst() { return this._shaderValues.getInt(TrailMaterial.BLEND_DST); } set depthTest(value) { this._shaderValues.setInt(TrailMaterial.DEPTH_TEST, value); } get depthTest() { return this._shaderValues.getInt(TrailMaterial.DEPTH_TEST); } clone() { var dest = new TrailMaterial(); this.cloneTo(dest); return dest; } } TrailMaterial.RENDERMODE_ALPHABLENDED = 0; TrailMaterial.RENDERMODE_ADDTIVE = 1; TrailMaterial.MAINTEXTURE = Shader3D.propertyNameToID("u_MainTexture"); TrailMaterial.TINTCOLOR = Shader3D.propertyNameToID("u_MainColor"); TrailMaterial.TILINGOFFSET = Shader3D.propertyNameToID("u_TilingOffset"); TrailMaterial.CULL = Shader3D.propertyNameToID("s_Cull"); TrailMaterial.BLEND = Shader3D.propertyNameToID("s_Blend"); TrailMaterial.BLEND_SRC = Shader3D.propertyNameToID("s_BlendSrc"); TrailMaterial.BLEND_DST = Shader3D.propertyNameToID("s_BlendDst"); TrailMaterial.DEPTH_TEST = Shader3D.propertyNameToID("s_DepthTest"); TrailMaterial.DEPTH_WRITE = Shader3D.propertyNameToID("s_DepthWrite"); class TextureMode { } TextureMode.Stretch = 0; TextureMode.Tile = 1; (function (TrailAlignment) { TrailAlignment[TrailAlignment["View"] = 0] = "View"; TrailAlignment[TrailAlignment["TransformZ"] = 1] = "TransformZ"; })(exports.TrailAlignment || (exports.TrailAlignment = {})); class VertexTrail { static get vertexDeclaration1() { return VertexTrail._vertexDeclaration1; } static get vertexDeclaration2() { return VertexTrail._vertexDeclaration2; } get vertexDeclaration() { return VertexTrail._vertexDeclaration1; } static __init__() { VertexTrail._vertexDeclaration1 = new VertexDeclaration(32, [new VertexElement(0, VertexElementFormat.Vector3, VertexTrail.TRAIL_POSITION0), new VertexElement(12, VertexElementFormat.Vector3, VertexTrail.TRAIL_OFFSETVECTOR), new VertexElement(24, VertexElementFormat.Single, VertexTrail.TRAIL_TIME0), new VertexElement(28, VertexElementFormat.Single, VertexTrail.TRAIL_TEXTURECOORDINATE0Y)]); VertexTrail._vertexDeclaration2 = new VertexDeclaration(20, [new VertexElement(0, VertexElementFormat.Single, VertexTrail.TRAIL_TEXTURECOORDINATE0X), new VertexElement(4, VertexElementFormat.Color, VertexTrail.TRAIL_COLOR)]); } } VertexTrail.TRAIL_POSITION0 = 0; VertexTrail.TRAIL_OFFSETVECTOR = 1; VertexTrail.TRAIL_TIME0 = 2; VertexTrail.TRAIL_TEXTURECOORDINATE0Y = 3; VertexTrail.TRAIL_TEXTURECOORDINATE0X = 4; VertexTrail.TRAIL_COLOR = 5; class TrailGeometry extends GeometryElement { constructor(owner) { super(); this._floatCountPerVertices1 = 8; this._floatCountPerVertices2 = 5; this._increaseSegementCount = 16; this._activeIndex = 0; this._endIndex = 0; this._needAddFirstVertex = false; this._isTempEndVertex = false; this._vertices1 = null; this._vertices2 = null; this._lastFixedVertexPosition = new Vector3(); this._bufferState = new BufferState(); this.tmpColor = new Color(); this._disappearBoundsMode = false; this._owner = owner; this._segementCount = this._increaseSegementCount; this._resizeData(this._segementCount, this._bufferState); var bounds = this._owner._owner.trailRenderer.bounds; var sprite3dPosition = this._owner._owner.transform.position; bounds.setMin(sprite3dPosition); bounds.setMax(sprite3dPosition); Laya.Render.supportWebGLPlusCulling && this._calculateBoundingBoxForNative(); } _resizeData(segementCount, bufferState) { this._subBirthTime = new Float32Array(segementCount); this._subDistance = new Float64Array(segementCount); var gl = Laya.LayaGL.instance; var vertexCount = segementCount * 2; var vertexDeclaration1 = VertexTrail.vertexDeclaration1; var vertexDeclaration2 = VertexTrail.vertexDeclaration2; var vertexBuffers = []; var vertexbuffer1Size = vertexCount * vertexDeclaration1.vertexStride; var vertexbuffer2Size = vertexCount * vertexDeclaration2.vertexStride; var memorySize = vertexbuffer1Size + vertexbuffer2Size; this._vertices1 = new Float32Array(vertexCount * this._floatCountPerVertices1); this._vertices2 = new Float32Array(vertexCount * this._floatCountPerVertices2); this._vertexBuffer1 = new VertexBuffer3D(vertexbuffer1Size, gl.STATIC_DRAW, false); this._vertexBuffer1.vertexDeclaration = vertexDeclaration1; this._vertexBuffer2 = new VertexBuffer3D(vertexbuffer2Size, gl.DYNAMIC_DRAW, false); this._vertexBuffer2.vertexDeclaration = vertexDeclaration2; vertexBuffers.push(this._vertexBuffer1); vertexBuffers.push(this._vertexBuffer2); bufferState.bind(); bufferState.applyVertexBuffers(vertexBuffers); bufferState.unBind(); Laya.Resource._addMemory(memorySize, memorySize); } _resetData() { var count = this._endIndex - this._activeIndex; var oldVertices1 = new Float32Array(this._vertices1.buffer, this._floatCountPerVertices1 * 2 * this._activeIndex * 4, this._floatCountPerVertices1 * 2 * count); var oldVertices2 = new Float32Array(this._vertices2.buffer, this._floatCountPerVertices2 * 2 * this._activeIndex * 4, this._floatCountPerVertices2 * 2 * count); var oldSubDistance = new Float64Array(this._subDistance.buffer, this._activeIndex * 8, count); var oldSubBirthTime = new Float32Array(this._subBirthTime.buffer, this._activeIndex * 4, count); if (count === this._segementCount) { this._vertexBuffer1.destroy(); this._vertexBuffer2.destroy(); var memorySize = this._vertexBuffer1._byteLength + this._vertexBuffer2._byteLength; Laya.Resource._addMemory(-memorySize, -memorySize); this._segementCount += this._increaseSegementCount; this._resizeData(this._segementCount, this._bufferState); } this._vertices1.set(oldVertices1, 0); this._vertices2.set(oldVertices2, 0); this._subDistance.set(oldSubDistance, 0); this._subBirthTime.set(oldSubBirthTime, 0); this._endIndex = count; this._activeIndex = 0; this._vertexBuffer1.setData(this._vertices1.buffer, 0, this._floatCountPerVertices1 * 2 * this._activeIndex * 4, this._floatCountPerVertices1 * 2 * count * 4); this._vertexBuffer2.setData(this._vertices2.buffer, 0, this._floatCountPerVertices2 * 2 * this._activeIndex * 4, this._floatCountPerVertices2 * 2 * count * 4); } _updateTrail(camera, lastPosition, position) { if (!Vector3.equals(lastPosition, position)) { if ((this._endIndex - this._activeIndex) === 0) this._addTrailByFirstPosition(camera, position); else this._addTrailByNextPosition(camera, position); } } _addTrailByFirstPosition(camera, position) { (this._endIndex === this._segementCount) && (this._resetData()); this._subDistance[this._endIndex] = 0; this._subBirthTime[this._endIndex] = this._owner._curtime; this._endIndex++; position.cloneTo(this._lastFixedVertexPosition); this._needAddFirstVertex = true; } _addTrailByNextPosition(camera, position) { var delVector3 = TrailGeometry._tempVector30; var pointAtoBVector3 = TrailGeometry._tempVector31; switch (this._owner.alignment) { case exports.TrailAlignment.View: var cameraMatrix = camera.viewMatrix; Vector3.transformCoordinate(position, cameraMatrix, TrailGeometry._tempVector33); Vector3.transformCoordinate(this._lastFixedVertexPosition, cameraMatrix, TrailGeometry._tempVector34); Vector3.subtract(TrailGeometry._tempVector33, TrailGeometry._tempVector34, delVector3); Vector3.cross(TrailGeometry._tempVector33, delVector3, pointAtoBVector3); break; case exports.TrailAlignment.TransformZ: Vector3.subtract(position, this._lastFixedVertexPosition, delVector3); var forward = TrailGeometry._tempVector32; this._owner._owner.transform.getForward(forward); Vector3.cross(delVector3, forward, pointAtoBVector3); break; } Vector3.normalize(pointAtoBVector3, pointAtoBVector3); Vector3.scale(pointAtoBVector3, this._owner.widthMultiplier / 2, pointAtoBVector3); var delLength = Vector3.scalarLength(delVector3); var tempEndIndex; var offset; if (this._needAddFirstVertex) { this._updateVerticesByPositionData(position, pointAtoBVector3, this._endIndex - 1); this._needAddFirstVertex = false; } if (delLength - this._owner.minVertexDistance >= MathUtils3D.zeroTolerance) { if (this._isTempEndVertex) { tempEndIndex = this._endIndex - 1; offset = delLength - this._subDistance[tempEndIndex]; this._updateVerticesByPosition(position, pointAtoBVector3, delLength, tempEndIndex); this._owner._totalLength += offset; } else { (this._endIndex === this._segementCount) && (this._resetData()); this._updateVerticesByPosition(position, pointAtoBVector3, delLength, this._endIndex); this._owner._totalLength += delLength; this._endIndex++; } position.cloneTo(this._lastFixedVertexPosition); this._isTempEndVertex = false; } else { if (this._isTempEndVertex) { tempEndIndex = this._endIndex - 1; offset = delLength - this._subDistance[tempEndIndex]; this._updateVerticesByPosition(position, pointAtoBVector3, delLength, tempEndIndex); this._owner._totalLength += offset; } else { (this._endIndex === this._segementCount) && (this._resetData()); this._updateVerticesByPosition(position, pointAtoBVector3, delLength, this._endIndex); this._owner._totalLength += delLength; this._endIndex++; } this._isTempEndVertex = true; } } _updateVerticesByPositionData(position, pointAtoBVector3, index) { var vertexOffset = this._floatCountPerVertices1 * 2 * index; var curtime = this._owner._curtime; this._vertices1[vertexOffset] = position.x; this._vertices1[vertexOffset + 1] = position.y; this._vertices1[vertexOffset + 2] = position.z; this._vertices1[vertexOffset + 3] = -pointAtoBVector3.x; this._vertices1[vertexOffset + 4] = -pointAtoBVector3.y; this._vertices1[vertexOffset + 5] = -pointAtoBVector3.z; this._vertices1[vertexOffset + 6] = curtime; this._vertices1[vertexOffset + 7] = 1.0; this._vertices1[vertexOffset + 8] = position.x; this._vertices1[vertexOffset + 9] = position.y; this._vertices1[vertexOffset + 10] = position.z; this._vertices1[vertexOffset + 11] = pointAtoBVector3.x; this._vertices1[vertexOffset + 12] = pointAtoBVector3.y; this._vertices1[vertexOffset + 13] = pointAtoBVector3.z; this._vertices1[vertexOffset + 14] = curtime; this._vertices1[vertexOffset + 15] = 0.0; var bounds = this._owner._owner.trailRenderer.bounds; var min = bounds.getMin(); var max = bounds.getMax(); var up = TrailGeometry._tempVector35; var down = TrailGeometry._tempVector36; var out = TrailGeometry._tempVector32; Vector3.add(position, pointAtoBVector3, up); Vector3.subtract(position, pointAtoBVector3, down); Vector3.min(down, up, out); Vector3.min(min, out, min); bounds.setMin(min); Vector3.max(up, down, out); Vector3.max(max, out, max); bounds.setMax(max); Laya.Render.supportWebGLPlusCulling && this._calculateBoundingBoxForNative(); var floatCount = this._floatCountPerVertices1 * 2; this._vertexBuffer1.setData(this._vertices1.buffer, vertexOffset * 4, vertexOffset * 4, floatCount * 4); } _updateVerticesByPosition(position, pointAtoBVector3, delDistance, index) { this._updateVerticesByPositionData(position, pointAtoBVector3, index); this._subDistance[index] = delDistance; this._subBirthTime[index] = this._owner._curtime; } _updateVertexBufferUV() { var bounds; var min, max; if (this._disappearBoundsMode) { bounds = this._owner._owner.trailRenderer.bounds; var sprite3dPosition = this._owner._owner.transform.position; bounds.setMin(sprite3dPosition); bounds.setMax(sprite3dPosition); min = bounds.getMin(); max = bounds.getMax(); Laya.Render.supportWebGLPlusCulling && this._calculateBoundingBoxForNative(); } var vertexCount = this._endIndex; var curLength = 0; var gradient = this._owner.colorGradient; var startAlphaIndex = gradient.colorAlphaKeysCount - 1; var startColorIndex = gradient.colorRGBKeysCount - 1; var totalLength = this._owner._totalLength; var stride = this._floatCountPerVertices2 * 2; for (var i = this._activeIndex; i < vertexCount; i++) { (i !== this._activeIndex) && (curLength += this._subDistance[i]); var uvX; var lerpFactor; if (this._owner.textureMode == TextureMode.Stretch) { uvX = 1.0 - curLength / totalLength; lerpFactor = uvX; } else { lerpFactor = 1.0 - curLength / totalLength; uvX = 1.0 - (totalLength - curLength); } startColorIndex = gradient.evaluateColorRGB(lerpFactor, this.tmpColor, startColorIndex, true); startAlphaIndex = gradient.evaluateColorAlpha(lerpFactor, this.tmpColor, startAlphaIndex, true); var index = i * stride; this._vertices2[index + 0] = uvX; this._vertices2[index + 1] = this.tmpColor.r; this._vertices2[index + 2] = this.tmpColor.g; this._vertices2[index + 3] = this.tmpColor.b; this._vertices2[index + 4] = this.tmpColor.a; this._vertices2[index + 5] = uvX; this._vertices2[index + 6] = this.tmpColor.r; this._vertices2[index + 7] = this.tmpColor.g; this._vertices2[index + 8] = this.tmpColor.b; this._vertices2[index + 9] = this.tmpColor.a; if (this._disappearBoundsMode) { var posOffset = this._floatCountPerVertices1 * 2 * i; var pos = TrailGeometry._tempVector32; var up = TrailGeometry._tempVector33; var side = TrailGeometry._tempVector34; pos.setValue(this._vertices1[posOffset + 0], this._vertices1[posOffset + 1], this._vertices1[posOffset + 2]); up.setValue(this._vertices1[posOffset + 3], this._vertices1[posOffset + 4], this._vertices1[posOffset + 5]); Vector3.add(pos, up, side); Vector3.min(side, min, min); Vector3.max(side, max, max); Vector3.subtract(pos, up, side); Vector3.min(side, min, min); Vector3.max(side, max, max); } } if (this._disappearBoundsMode) { bounds.setMin(min); bounds.setMax(max); this._disappearBoundsMode = false; Laya.Render.supportWebGLPlusCulling && this._calculateBoundingBoxForNative(); } var offset = this._activeIndex * stride; this._vertexBuffer2.setData(this._vertices2.buffer, offset * 4, offset * 4, (vertexCount * stride - offset) * 4); } _updateDisappear() { var count = this._endIndex; for (var i = this._activeIndex; i < count; i++) { if (this._owner._curtime - this._subBirthTime[i] >= this._owner.time + MathUtils3D.zeroTolerance) { var nextIndex = i + 1; if (nextIndex !== count) this._owner._totalLength -= this._subDistance[nextIndex]; if (this._isTempEndVertex && (nextIndex === count - 1)) { var offset = this._floatCountPerVertices1 * i * 2; var fixedPos = this._lastFixedVertexPosition; fixedPos.x = this._vertices1[0]; fixedPos.y = this._vertices1[1]; fixedPos.z = this._vertices1[2]; this._isTempEndVertex = false; } this._activeIndex++; this._disappearBoundsMode = true; } else { break; } } } _getType() { return TrailGeometry._type; } _prepareRender(state) { return this._endIndex - this._activeIndex > 1; } _render(state) { this._bufferState.bind(); var gl = Laya.LayaGL.instance; var start = this._activeIndex * 2; var count = this._endIndex * 2 - start; gl.drawArrays(gl.TRIANGLE_STRIP, start, count); Laya.Stat.renderBatches++; Laya.Stat.trianglesFaces += count - 2; } destroy() { super.destroy(); var memorySize = this._vertexBuffer1._byteLength + this._vertexBuffer2._byteLength; Laya.Resource._addMemory(-memorySize, -memorySize); this._bufferState.destroy(); this._vertexBuffer1.destroy(); this._vertexBuffer2.destroy(); this._bufferState = null; this._vertices1 = null; this._vertexBuffer1 = null; this._vertices2 = null; this._vertexBuffer2 = null; this._subBirthTime = null; this._subDistance = null; this._lastFixedVertexPosition = null; this._disappearBoundsMode = false; } _calculateBoundingBoxForNative() { var trail = this._owner._owner.trailRenderer; var bounds = trail.bounds; var min = bounds.getMin(); var max = bounds.getMax(); var buffer = FrustumCulling._cullingBuffer; buffer[trail._cullingBufferIndex + 1] = min.x; buffer[trail._cullingBufferIndex + 2] = min.y; buffer[trail._cullingBufferIndex + 3] = min.z; buffer[trail._cullingBufferIndex + 4] = max.x; buffer[trail._cullingBufferIndex + 5] = max.y; buffer[trail._cullingBufferIndex + 6] = max.z; } clear() { this._activeIndex = 0; this._endIndex = 0; this._disappearBoundsMode = false; this._subBirthTime.fill(0); this._subDistance.fill(0); this._segementCount = 0; this._isTempEndVertex = false; this._needAddFirstVertex = false; this._lastFixedVertexPosition.setValue(0, 0, 0); } } TrailGeometry.ALIGNMENT_VIEW = 0; TrailGeometry.ALIGNMENT_TRANSFORM_Z = 1; TrailGeometry._tempVector30 = new Vector3(); TrailGeometry._tempVector31 = new Vector3(); TrailGeometry._tempVector32 = new Vector3(); TrailGeometry._tempVector33 = new Vector3(); TrailGeometry._tempVector34 = new Vector3(); TrailGeometry._tempVector35 = new Vector3(); TrailGeometry._tempVector36 = new Vector3(); TrailGeometry._type = GeometryElement._typeCounter++; class TrailFilter { constructor(owner) { this._totalLength = 0; this._lastPosition = new Vector3(); this._curtime = 0; this.alignment = TrailFilter.ALIGNMENT_VIEW; this._owner = owner; this._initDefaultData(); this.addRenderElement(); } get time() { return this._time; } set time(value) { this._time = value; this._owner._render._shaderValues.setNumber(TrailFilter.LIFETIME, value); } get minVertexDistance() { return this._minVertexDistance; } set minVertexDistance(value) { this._minVertexDistance = value; } get widthMultiplier() { return this._widthMultiplier; } set widthMultiplier(value) { this._widthMultiplier = value; } get widthCurve() { return this._widthCurve; } set widthCurve(value) { this._widthCurve = value; var widthCurveFloatArray = new Float32Array(value.length * 4); var i, j, index = 0; for (i = 0, j = value.length; i < j; i++) { widthCurveFloatArray[index++] = value[i].time; widthCurveFloatArray[index++] = value[i].inTangent; widthCurveFloatArray[index++] = value[i].outTangent; widthCurveFloatArray[index++] = value[i].value; } this._owner._render._shaderValues.setBuffer(TrailFilter.WIDTHCURVE, widthCurveFloatArray); this._owner._render._shaderValues.setInt(TrailFilter.WIDTHCURVEKEYLENGTH, value.length); } get colorGradient() { return this._colorGradient; } set colorGradient(value) { this._colorGradient = value; } get textureMode() { return this._textureMode; } set textureMode(value) { this._textureMode = value; } addRenderElement() { var render = this._owner._render; var elements = render._renderElements; var material = render.sharedMaterials[0]; (material) || (material = TrailMaterial.defaultMaterial); var element = new RenderElement(); element.setTransform(this._owner._transform); element.render = render; element.material = material; this._trialGeometry = new TrailGeometry(this); element.setGeometry(this._trialGeometry); elements.push(element); } _update(state) { var render = this._owner._render; this._curtime += state.scene.timer._delta / 1000; render._shaderValues.setNumber(TrailFilter.CURTIME, this._curtime); var curPos = this._owner.transform.position; var element = render._renderElements[0]._geometry; element._updateDisappear(); element._updateTrail(state.camera, this._lastPosition, curPos); element._updateVertexBufferUV(); curPos.cloneTo(this._lastPosition); } _initDefaultData() { this.time = 5.0; this.minVertexDistance = 0.1; this.widthMultiplier = 1; this.textureMode = TextureMode.Stretch; var widthKeyFrames = []; var widthKeyFrame1 = new FloatKeyframe(); widthKeyFrame1.time = 0; widthKeyFrame1.inTangent = 0; widthKeyFrame1.outTangent = 0; widthKeyFrame1.value = 1; widthKeyFrames.push(widthKeyFrame1); var widthKeyFrame2 = new FloatKeyframe(); widthKeyFrame2.time = 1; widthKeyFrame2.inTangent = 0; widthKeyFrame2.outTangent = 0; widthKeyFrame2.value = 1; widthKeyFrames.push(widthKeyFrame2); this.widthCurve = widthKeyFrames; var gradient = new Gradient(2, 2); gradient.mode = GradientMode.Blend; gradient.addColorRGB(0, Color.WHITE); gradient.addColorRGB(1, Color.WHITE); gradient.addColorAlpha(0, 1); gradient.addColorAlpha(1, 1); this.colorGradient = gradient; } destroy() { this._trialGeometry.destroy(); this._trialGeometry = null; this._widthCurve = null; this._colorGradient = null; } clear() { this._trialGeometry.clear(); this._lastPosition.setValue(0, 0, 0); this._curtime = 0; this._totalLength = 0; } } TrailFilter.CURTIME = Shader3D.propertyNameToID("u_CurTime"); TrailFilter.LIFETIME = Shader3D.propertyNameToID("u_LifeTime"); TrailFilter.WIDTHCURVE = Shader3D.propertyNameToID("u_WidthCurve"); TrailFilter.WIDTHCURVEKEYLENGTH = Shader3D.propertyNameToID("u_WidthCurveKeyLength"); TrailFilter.ALIGNMENT_VIEW = 0; TrailFilter.ALIGNMENT_TRANSFORM_Z = 1; class TrailRenderer extends BaseRender { constructor(owner) { super(owner); this._projectionViewWorldMatrix = new Matrix4x4(); } _calculateBoundingBox() { } _needRender(boundFrustum, context) { this._owner.trailFilter._update(context); if (boundFrustum) return boundFrustum.intersects(this.bounds._getBoundBox()); else return true; } _updateForNative(context) { this._owner.trailFilter._update(context); } _renderUpdate(state, transform) { super._renderUpdate(state, transform); } _renderUpdateWithCamera(context, transform) { var projectionView = context.projectionViewMatrix; if (transform) { Matrix4x4.multiply(projectionView, transform.worldMatrix, this._projectionViewWorldMatrix); this._shaderValues.setMatrix4x4(Sprite3D.MVPMATRIX, this._projectionViewWorldMatrix); } else { this._shaderValues.setMatrix4x4(Sprite3D.MVPMATRIX, projectionView); } } } class TrailSprite3D extends RenderableSprite3D { constructor(name = null) { super(name); this._render = new TrailRenderer(this); this._geometryFilter = new TrailFilter(this); } static __init__() { } get trailFilter() { return this._geometryFilter; } get trailRenderer() { return this._render; } _parse(data, spriteMap) { super._parse(data, spriteMap); var render = this._render; var filter = this._geometryFilter; var i, j; var materials = data.materials; if (materials) { var sharedMaterials = render.sharedMaterials; var materialCount = materials.length; sharedMaterials.length = materialCount; for (i = 0; i < materialCount; i++) sharedMaterials[i] = Laya.Loader.getRes(materials[i].path); render.sharedMaterials = sharedMaterials; } filter.time = data.time; filter.minVertexDistance = data.minVertexDistance; filter.widthMultiplier = data.widthMultiplier; filter.textureMode = data.textureMode; (data.alignment != null) && (filter.alignment = data.alignment); var widthCurve = []; var widthCurveData = data.widthCurve; for (i = 0, j = widthCurveData.length; i < j; i++) { var trailkeyframe = new FloatKeyframe(); trailkeyframe.time = widthCurveData[i].time; trailkeyframe.inTangent = widthCurveData[i].inTangent; trailkeyframe.outTangent = widthCurveData[i].outTangent; trailkeyframe.value = widthCurveData[i].value; widthCurve.push(trailkeyframe); } filter.widthCurve = widthCurve; var colorGradientData = data.colorGradient; var colorKeys = colorGradientData.colorKeys; var alphaKeys = colorGradientData.alphaKeys; var colorGradient = new Gradient(colorKeys.length, alphaKeys.length); colorGradient.mode = colorGradientData.mode; for (i = 0, j = colorKeys.length; i < j; i++) { var colorKey = colorKeys[i]; colorGradient.addColorRGB(colorKey.time, new Color(colorKey.value[0], colorKey.value[1], colorKey.value[2], 1.0)); } for (i = 0, j = alphaKeys.length; i < j; i++) { var alphaKey = alphaKeys[i]; colorGradient.addColorAlpha(alphaKey.time, alphaKey.value); } filter.colorGradient = colorGradient; } _onActive() { super._onActive(); this._transform.position.cloneTo(this._geometryFilter._lastPosition); } _cloneTo(destObject, srcSprite, dstSprite) { super._cloneTo(destObject, srcSprite, dstSprite); var i, j; var destTrailSprite3D = destObject; var destTrailFilter = destTrailSprite3D.trailFilter; destTrailFilter.time = this.trailFilter.time; destTrailFilter.minVertexDistance = this.trailFilter.minVertexDistance; destTrailFilter.widthMultiplier = this.trailFilter.widthMultiplier; destTrailFilter.textureMode = this.trailFilter.textureMode; destTrailFilter.alignment = this.trailFilter.alignment; var widthCurveData = this.trailFilter.widthCurve; var widthCurve = []; for (i = 0, j = widthCurveData.length; i < j; i++) { var keyFrame = new FloatKeyframe(); widthCurveData[i].cloneTo(keyFrame); widthCurve.push(keyFrame); } destTrailFilter.widthCurve = widthCurve; var destColorGradient = new Gradient(this.trailFilter.colorGradient.maxColorRGBKeysCount, this.trailFilter.colorGradient.maxColorAlphaKeysCount); this.trailFilter.colorGradient.cloneTo(destColorGradient); destTrailFilter.colorGradient = destColorGradient; var destTrailRender = destTrailSprite3D.trailRenderer; destTrailRender.sharedMaterial = this.trailRenderer.sharedMaterial; } destroy(destroyChild = true) { if (this.destroyed) return; super.destroy(destroyChild); this._geometryFilter.destroy(); this._geometryFilter = null; } clear() { this._geometryFilter.clear(); } _create() { return new TrailSprite3D(); } } class VertexPositionTerrain { constructor(position, normal, textureCoord0, textureCoord1) { this._position = position; this._normal = normal; this._textureCoord0 = textureCoord0; this._textureCoord1 = textureCoord1; } static __init__() { VertexPositionTerrain._vertexDeclaration = new VertexDeclaration(40, [new VertexElement(0, VertexElementFormat.Vector3, VertexPositionTerrain.TERRAIN_POSITION0), new VertexElement(12, VertexElementFormat.Vector3, VertexPositionTerrain.TERRAIN_NORMAL0), new VertexElement(24, VertexElementFormat.Vector2, VertexPositionTerrain.TERRAIN_TEXTURECOORDINATE0), new VertexElement(32, VertexElementFormat.Vector2, VertexPositionTerrain.TERRAIN_TEXTURECOORDINATE1)]); } static get vertexDeclaration() { return VertexPositionTerrain._vertexDeclaration; } get position() { return this._position; } get normal() { return this._normal; } get textureCoord0() { return this._textureCoord0; } get textureCoord1() { return this._textureCoord1; } get vertexDeclaration() { return VertexPositionTerrain._vertexDeclaration; } } VertexPositionTerrain.TERRAIN_POSITION0 = 0; VertexPositionTerrain.TERRAIN_NORMAL0 = 1; VertexPositionTerrain.TERRAIN_TEXTURECOORDINATE0 = 2; VertexPositionTerrain.TERRAIN_TEXTURECOORDINATE1 = 3; class BulletInteractive { } BulletInteractive._interactive = { "getWorldTransform": (rigidBodyID, worldTransPointer) => { }, "setWorldTransform": (rigidBodyID, worldTransPointer) => { var rigidBody = PhysicsComponent._physicObjectsMap[rigidBodyID]; rigidBody._simulation._updatedRigidbodies++; rigidBody._updateTransformComponent(worldTransPointer); } }; class PhysicsCollider extends PhysicsTriggerComponent { constructor(collisionGroup = Physics3DUtils.COLLISIONFILTERGROUP_DEFAULTFILTER, canCollideWith = Physics3DUtils.COLLISIONFILTERGROUP_ALLFILTER) { super(collisionGroup, canCollideWith); this._enableProcessCollisions = false; } _addToSimulation() { this._simulation._addPhysicsCollider(this, this._collisionGroup, this._canCollideWith); } _removeFromSimulation() { this._simulation._removePhysicsCollider(this); } _parse(data) { (data.friction != null) && (this.friction = data.friction); (data.rollingFriction != null) && (this.rollingFriction = data.rollingFriction); (data.restitution != null) && (this.restitution = data.restitution); (data.isTrigger != null) && (this.isTrigger = data.isTrigger); super._parse(data); this._parseShape(data.shapes); } _onAdded() { var bt = Physics3D._bullet; var btColObj = bt.btCollisionObject_create(); bt.btCollisionObject_setUserIndex(btColObj, this.id); bt.btCollisionObject_forceActivationState(btColObj, PhysicsComponent.ACTIVATIONSTATE_DISABLE_SIMULATION); var flags = bt.btCollisionObject_getCollisionFlags(btColObj); if (this.owner.isStatic) { if ((flags & PhysicsComponent.COLLISIONFLAGS_KINEMATIC_OBJECT) > 0) flags = flags ^ PhysicsComponent.COLLISIONFLAGS_KINEMATIC_OBJECT; flags = flags | PhysicsComponent.COLLISIONFLAGS_STATIC_OBJECT; } else { if ((flags & PhysicsComponent.COLLISIONFLAGS_STATIC_OBJECT) > 0) flags = flags ^ PhysicsComponent.COLLISIONFLAGS_STATIC_OBJECT; flags = flags | PhysicsComponent.COLLISIONFLAGS_KINEMATIC_OBJECT; } bt.btCollisionObject_setCollisionFlags(btColObj, flags); this._btColliderObject = btColObj; super._onAdded(); } } class SubMesh extends GeometryElement { constructor(mesh) { super(); this._id = ++SubMesh._uniqueIDCounter; this._mesh = mesh; this._boneIndicesList = []; this._subIndexBufferStart = []; this._subIndexBufferCount = []; } get indexCount() { return this._indexCount; } _setIndexRange(indexStart, indexCount) { this._indexStart = indexStart; this._indexCount = indexCount; this._indices = new Uint16Array(this._indexBuffer.getData().buffer, indexStart * 2, indexCount); } _getType() { return SubMesh._type; } _prepareRender(state) { this._mesh._uploadVerticesData(); return true; } _render(state) { var mesh = this._mesh; if (mesh.indexFormat === exports.IndexFormat.UInt32 && !Laya.LayaGL.layaGPUInstance.supportElementIndexUint32()) { console.warn("SubMesh:this device do not support IndexFormat.UInt32."); return; } var gl = Laya.LayaGL.instance; var skinnedDatas = state.renderElement.render._skinnedData; var glIndexFormat; var byteCount; switch (mesh.indexFormat) { case exports.IndexFormat.UInt32: glIndexFormat = gl.UNSIGNED_INT; byteCount = 4; break; case exports.IndexFormat.UInt16: glIndexFormat = gl.UNSIGNED_SHORT; byteCount = 2; break; case exports.IndexFormat.UInt8: glIndexFormat = gl.UNSIGNED_BYTE; byteCount = 1; break; } mesh._bufferState.bind(); if (skinnedDatas) { var subSkinnedDatas = skinnedDatas[this._indexInMesh]; for (var i = 0, n = this._boneIndicesList.length; i < n; i++) { state.shader.uploadCustomUniform(SkinnedMeshSprite3D.BONES, subSkinnedDatas[i]); gl.drawElements(gl.TRIANGLES, this._subIndexBufferCount[i], glIndexFormat, this._subIndexBufferStart[i] * byteCount); } } else { gl.drawElements(gl.TRIANGLES, this._indexCount, glIndexFormat, this._indexStart * byteCount); } Laya.Stat.trianglesFaces += this._indexCount / 3; Laya.Stat.renderBatches++; } getIndices() { if (this._mesh._isReadable) return this._indices.slice(); else throw "SubMesh:can't get indices on subMesh,mesh's isReadable must be true."; } setIndices(indices) { this._indexBuffer.setData(indices, this._indexStart, 0, this._indexCount); } destroy() { if (this._destroyed) return; super.destroy(); this._indexBuffer.destroy(); this._indexBuffer = null; this._mesh = null; this._boneIndicesList = null; this._subIndexBufferStart = null; this._subIndexBufferCount = null; this._skinAnimationDatas = null; } } SubMesh._uniqueIDCounter = 0; SubMesh._type = GeometryElement._typeCounter++; class skinnedMatrixCache { constructor(subMeshIndex, batchIndex, batchBoneIndex) { this.subMeshIndex = subMeshIndex; this.batchIndex = batchIndex; this.batchBoneIndex = batchBoneIndex; } } class Mesh extends Laya.Resource { constructor(isReadable = true) { super(); this._tempVector30 = new Vector3(); this._tempVector31 = new Vector3(); this._tempVector32 = new Vector3(); this._minVerticesUpdate = -1; this._maxVerticesUpdate = -1; this._needUpdateBounds = true; this._bounds = new Bounds(new Vector3(), new Vector3()); this._bufferState = new BufferState(); this._instanceBufferState = new BufferState(); this._vertexBuffer = null; this._indexBuffer = null; this._skinnedMatrixCaches = []; this._vertexCount = 0; this._indexFormat = exports.IndexFormat.UInt16; this._isReadable = isReadable; this._subMeshes = []; } static __init__() { var physics3D = Physics3D._bullet; if (physics3D) { Mesh._nativeTempVector30 = physics3D.btVector3_create(0, 0, 0); Mesh._nativeTempVector31 = physics3D.btVector3_create(0, 0, 0); Mesh._nativeTempVector32 = physics3D.btVector3_create(0, 0, 0); } } static load(url, complete) { Laya.ILaya.loader.create(url, complete, null, Mesh.MESH); } get inverseAbsoluteBindPoses() { return this._inverseBindPoses; } get vertexCount() { return this._vertexCount; } get indexCount() { return this._indexBuffer.indexCount; } get subMeshCount() { return this._subMeshes.length; } get bounds() { return this._bounds; } set bounds(value) { if (this._bounds !== value) value.cloneTo(this._bounds); } get indexFormat() { return this._indexFormat; } _getPositionElement(vertexBuffer) { var vertexElements = vertexBuffer.vertexDeclaration._vertexElements; for (var i = 0, n = vertexElements.length; i < n; i++) { var vertexElement = vertexElements[i]; if (vertexElement._elementFormat === VertexElementFormat.Vector3 && vertexElement._elementUsage === VertexMesh.MESH_POSITION0) return vertexElement; } return null; } _getVerticeElementData(data, elementUsage) { data.length = this._vertexCount; var verDec = this._vertexBuffer.vertexDeclaration; var element = verDec.getVertexElementByUsage(elementUsage); if (element) { var uint8Vertices = this._vertexBuffer.getUint8Data(); var floatVertices = this._vertexBuffer.getFloat32Data(); var uint8VerStr = verDec.vertexStride; var floatVerStr = uint8VerStr / 4; var uint8EleOffset = element._offset; var floatEleOffset = uint8EleOffset / 4; switch (elementUsage) { case VertexMesh.MESH_TEXTURECOORDINATE0: case VertexMesh.MESH_TEXTURECOORDINATE1: for (var i = 0; i < this._vertexCount; i++) { var offset = floatVerStr * i + floatEleOffset; data[i] = new Vector2(floatVertices[offset], floatVertices[offset + 1]); } break; case VertexMesh.MESH_POSITION0: case VertexMesh.MESH_NORMAL0: for (var i = 0; i < this._vertexCount; i++) { var offset = floatVerStr * i + floatEleOffset; data[i] = new Vector3(floatVertices[offset], floatVertices[offset + 1], floatVertices[offset + 2]); } break; case VertexMesh.MESH_TANGENT0: case VertexMesh.MESH_BLENDWEIGHT0: for (var i = 0; i < this._vertexCount; i++) { var offset = floatVerStr * i + floatEleOffset; data[i] = new Vector4(floatVertices[offset], floatVertices[offset + 1], floatVertices[offset + 2], floatVertices[offset + 3]); } break; case VertexMesh.MESH_COLOR0: for (var i = 0; i < this._vertexCount; i++) { var offset = floatVerStr * i + floatEleOffset; data[i] = new Color(floatVertices[offset], floatVertices[offset + 1], floatVertices[offset + 2], floatVertices[offset + 3]); } break; case VertexMesh.MESH_BLENDINDICES0: for (var i = 0; i < this._vertexCount; i++) { var offset = uint8VerStr * i + uint8EleOffset; data[i] = new Vector4(uint8Vertices[offset], uint8Vertices[offset + 1], uint8Vertices[offset + 2], uint8Vertices[offset + 3]); } break; default: throw "Mesh:Unknown elementUsage."; } } } _setVerticeElementData(data, elementUsage) { var verDec = this._vertexBuffer.vertexDeclaration; var element = verDec.getVertexElementByUsage(elementUsage); if (element) { var uint8Vertices = this._vertexBuffer.getUint8Data(); var floatVertices = this._vertexBuffer.getFloat32Data(); var uint8VerStr = verDec.vertexStride; var float8VerStr = uint8VerStr / 4; var uint8EleOffset = element._offset; var floatEleOffset = uint8EleOffset / 4; switch (elementUsage) { case VertexMesh.MESH_TEXTURECOORDINATE0: case VertexMesh.MESH_TEXTURECOORDINATE1: for (var i = 0, n = data.length; i < n; i++) { var offset = float8VerStr * i + floatEleOffset; var vec2 = data[i]; floatVertices[offset] = vec2.x; floatVertices[offset + 1] = vec2.y; } break; case VertexMesh.MESH_POSITION0: case VertexMesh.MESH_NORMAL0: for (var i = 0, n = data.length; i < n; i++) { var offset = float8VerStr * i + floatEleOffset; var vec3 = data[i]; floatVertices[offset] = vec3.x; floatVertices[offset + 1] = vec3.y; floatVertices[offset + 2] = vec3.z; } break; case VertexMesh.MESH_TANGENT0: case VertexMesh.MESH_BLENDWEIGHT0: for (var i = 0, n = data.length; i < n; i++) { var offset = float8VerStr * i + floatEleOffset; var vec4 = data[i]; floatVertices[offset] = vec4.x; floatVertices[offset + 1] = vec4.y; floatVertices[offset + 2] = vec4.z; floatVertices[offset + 3] = vec4.w; } break; case VertexMesh.MESH_COLOR0: for (var i = 0, n = data.length; i < n; i++) { var offset = float8VerStr * i + floatEleOffset; var cor = data[i]; floatVertices[offset] = cor.r; floatVertices[offset + 1] = cor.g; floatVertices[offset + 2] = cor.b; floatVertices[offset + 3] = cor.a; } break; case VertexMesh.MESH_BLENDINDICES0: for (var i = 0, n = data.length; i < n; i++) { var offset = uint8VerStr * i + uint8EleOffset; var vec4 = data[i]; uint8Vertices[offset] = vec4.x; uint8Vertices[offset + 1] = vec4.y; uint8Vertices[offset + 2] = vec4.z; uint8Vertices[offset + 3] = vec4.w; } break; default: throw "Mesh:Unknown elementUsage."; } this._minVerticesUpdate = 0; this._maxVerticesUpdate = Number.MAX_SAFE_INTEGER; } else { console.warn("Mesh: the mesh don't have this VertexElement."); } } _disposeResource() { for (var i = 0, n = this._subMeshes.length; i < n; i++) this._subMeshes[i].destroy(); this._btTriangleMesh && Physics3D._bullet.btStridingMeshInterface_destroy(this._btTriangleMesh); this._vertexBuffer.destroy(); this._indexBuffer.destroy(); this._bufferState.destroy(); this._instanceBufferState.destroy(); this._setCPUMemory(0); this._setGPUMemory(0); this._bufferState = null; this._instanceBufferState = null; this._vertexBuffer = null; this._indexBuffer = null; this._subMeshes = null; this._btTriangleMesh = null; this._indexBuffer = null; this._boneNames = null; this._inverseBindPoses = null; } _setSubMeshes(subMeshes) { this._subMeshes = subMeshes; for (var i = 0, n = subMeshes.length; i < n; i++) subMeshes[i]._indexInMesh = i; } _setBuffer(vertexBuffer, indexBuffer) { var bufferState = this._bufferState; bufferState.bind(); bufferState.applyVertexBuffer(vertexBuffer); bufferState.applyIndexBuffer(indexBuffer); bufferState.unBind(); var instanceBufferState = this._instanceBufferState; instanceBufferState.bind(); instanceBufferState.applyVertexBuffer(vertexBuffer); instanceBufferState.applyInstanceVertexBuffer(SubMeshInstanceBatch.instance.instanceWorldMatrixBuffer); instanceBufferState.applyInstanceVertexBuffer(SubMeshInstanceBatch.instance.instanceMVPMatrixBuffer); instanceBufferState.applyIndexBuffer(indexBuffer); instanceBufferState.unBind(); } _getPhysicMesh() { if (!this._btTriangleMesh) { var bt = Physics3D._bullet; var triangleMesh = bt.btTriangleMesh_create(); var nativePositio0 = Mesh._nativeTempVector30; var nativePositio1 = Mesh._nativeTempVector31; var nativePositio2 = Mesh._nativeTempVector32; var position0 = this._tempVector30; var position1 = this._tempVector31; var position2 = this._tempVector32; var vertexBuffer = this._vertexBuffer; var positionElement = this._getPositionElement(vertexBuffer); var verticesData = vertexBuffer.getFloat32Data(); var floatCount = vertexBuffer.vertexDeclaration.vertexStride / 4; var posOffset = positionElement._offset / 4; var indices = this._indexBuffer.getData(); for (var i = 0, n = indices.length; i < n; i += 3) { var p0Index = indices[i] * floatCount + posOffset; var p1Index = indices[i + 1] * floatCount + posOffset; var p2Index = indices[i + 2] * floatCount + posOffset; position0.setValue(verticesData[p0Index], verticesData[p0Index + 1], verticesData[p0Index + 2]); position1.setValue(verticesData[p1Index], verticesData[p1Index + 1], verticesData[p1Index + 2]); position2.setValue(verticesData[p2Index], verticesData[p2Index + 1], verticesData[p2Index + 2]); Utils3D._convertToBulletVec3(position0, nativePositio0, true); Utils3D._convertToBulletVec3(position1, nativePositio1, true); Utils3D._convertToBulletVec3(position2, nativePositio2, true); bt.btTriangleMesh_addTriangle(triangleMesh, nativePositio0, nativePositio1, nativePositio2, true); } this._btTriangleMesh = triangleMesh; } return this._btTriangleMesh; } _uploadVerticesData() { var min = this._minVerticesUpdate; var max = this._maxVerticesUpdate; if (min !== -1 && max !== -1) { var offset = min; this._vertexBuffer.setData(this._vertexBuffer.getUint8Data().buffer, offset, offset, max - min); this._minVerticesUpdate = -1; this._maxVerticesUpdate = -1; } } getSubMesh(index) { return this._subMeshes[index]; } getPositions(positions) { if (this._isReadable) this._getVerticeElementData(positions, VertexMesh.MESH_POSITION0); else throw "Mesh:can't get positions on mesh,isReadable must be true."; } setPositions(positions) { if (this._isReadable) { this._setVerticeElementData(positions, VertexMesh.MESH_POSITION0); this._needUpdateBounds = true; } else { throw "Mesh:setPosition() need isReadable must be true or use setVertices()."; } } getColors(colors) { if (this._isReadable) this._getVerticeElementData(colors, VertexMesh.MESH_COLOR0); else throw "Mesh:can't get colors on mesh,isReadable must be true."; } setColors(colors) { if (this._isReadable) this._setVerticeElementData(colors, VertexMesh.MESH_COLOR0); else throw "Mesh:setColors() need isReadable must be true or use setVertices()."; } getUVs(uvs, channel = 0) { if (this._isReadable) { switch (channel) { case 0: this._getVerticeElementData(uvs, VertexMesh.MESH_TEXTURECOORDINATE0); break; case 1: this._getVerticeElementData(uvs, VertexMesh.MESH_TEXTURECOORDINATE1); break; default: throw "Mesh:Invalid channel."; } } else { throw "Mesh:can't get uvs on mesh,isReadable must be true."; } } setUVs(uvs, channel = 0) { if (this._isReadable) { switch (channel) { case 0: this._setVerticeElementData(uvs, VertexMesh.MESH_TEXTURECOORDINATE0); break; case 1: this._setVerticeElementData(uvs, VertexMesh.MESH_TEXTURECOORDINATE1); break; default: throw "Mesh:Invalid channel."; } } else { throw "Mesh:setUVs() need isReadable must be true or use setVertices()."; } } getNormals(normals) { if (this._isReadable) this._getVerticeElementData(normals, VertexMesh.MESH_NORMAL0); else throw "Mesh:can't get colors on mesh,isReadable must be true."; } setNormals(normals) { if (this._isReadable) this._setVerticeElementData(normals, VertexMesh.MESH_NORMAL0); else throw "Mesh:setNormals() need must be true or use setVertices()."; } getTangents(tangents) { if (this._isReadable) this._getVerticeElementData(tangents, VertexMesh.MESH_TANGENT0); else throw "Mesh:can't get colors on mesh,isReadable must be true."; } setTangents(tangents) { if (this._isReadable) this._setVerticeElementData(tangents, VertexMesh.MESH_TANGENT0); else throw "Mesh:setTangents() need isReadable must be true or use setVertices()."; } getBoneWeights(boneWeights) { if (this._isReadable) this._getVerticeElementData(boneWeights, VertexMesh.MESH_BLENDWEIGHT0); else throw "Mesh:can't get boneWeights on mesh,isReadable must be true."; } setBoneWeights(boneWeights) { if (this._isReadable) this._setVerticeElementData(boneWeights, VertexMesh.MESH_BLENDWEIGHT0); else throw "Mesh:setBoneWeights() need isReadable must be true or use setVertices()."; } getBoneIndices(boneIndices) { if (this._isReadable) this._getVerticeElementData(boneIndices, VertexMesh.MESH_BLENDINDICES0); else throw "Mesh:can't get boneIndices on mesh,isReadable must be true."; } setBoneIndices(boneIndices) { if (this._isReadable) this._setVerticeElementData(boneIndices, VertexMesh.MESH_BLENDINDICES0); else throw "Mesh:setBoneIndices() need isReadable must be true or use setVertices()."; } markAsUnreadbale() { this._uploadVerticesData(); this._vertexBuffer.markAsUnreadbale(); this._isReadable = false; } getVertexDeclaration() { return this._vertexBuffer._vertexDeclaration; } getVertices() { if (this._isReadable) return this._vertexBuffer.getUint8Data().buffer.slice(0); else throw "Mesh:can't get vertices on mesh,isReadable must be true."; } setVertices(vertices) { this._vertexBuffer.setData(vertices); this._needUpdateBounds = true; } getIndices() { if (this._isReadable) return this._indexBuffer.getData().slice(); else throw "Mesh:can't get indices on subMesh,mesh's isReadable must be true."; } setIndices(indices) { var format; if (indices instanceof Uint32Array) format = exports.IndexFormat.UInt32; else if (indices instanceof Uint16Array) format = exports.IndexFormat.UInt16; else if (indices instanceof Uint8Array) format = exports.IndexFormat.UInt8; var indexBuffer = this._indexBuffer; if (this._indexFormat !== format || indexBuffer.indexCount !== indices.length) { indexBuffer.destroy(); this._indexBuffer = indexBuffer = new IndexBuffer3D(format, indices.length, Laya.LayaGL.instance.STATIC_DRAW, this._isReadable); } indexBuffer.setData(indices); this._indexFormat = format; } calculateBounds() { if (this._isReadable) { if (this._needUpdateBounds) { var min = this._tempVector30; var max = this._tempVector31; min.x = min.y = min.z = Number.MAX_VALUE; max.x = max.y = max.z = -Number.MAX_VALUE; var vertexBuffer = this._vertexBuffer; var positionElement = this._getPositionElement(vertexBuffer); var verticesData = vertexBuffer.getFloat32Data(); var floatCount = vertexBuffer.vertexDeclaration.vertexStride / 4; var posOffset = positionElement._offset / 4; for (var j = 0, m = verticesData.length; j < m; j += floatCount) { var ofset = j + posOffset; var pX = verticesData[ofset]; var pY = verticesData[ofset + 1]; var pZ = verticesData[ofset + 2]; min.x = Math.min(min.x, pX); min.y = Math.min(min.y, pY); min.z = Math.min(min.z, pZ); max.x = Math.max(max.x, pX); max.y = Math.max(max.y, pY); max.z = Math.max(max.z, pZ); } this._bounds.setMin(min); this._bounds.setMax(max); this._needUpdateBounds = false; } } else { throw "Mesh:can't calculate bounds on subMesh,mesh's isReadable must be true."; } } cloneTo(destObject) { var destMesh = destObject; var vb = this._vertexBuffer; var destVB = new VertexBuffer3D(vb._byteLength, vb.bufferUsage, vb.canRead); destVB.vertexDeclaration = vb.vertexDeclaration; destVB.setData(vb.getUint8Data().slice().buffer); destMesh._vertexBuffer = destVB; destMesh._vertexCount = this._vertexCount; var ib = this._indexBuffer; var destIB = new IndexBuffer3D(exports.IndexFormat.UInt16, ib.indexCount, ib.bufferUsage, ib.canRead); destIB.setData(ib.getData().slice()); destMesh._indexBuffer = destIB; destMesh._setBuffer(destMesh._vertexBuffer, destIB); destMesh._setCPUMemory(this.cpuMemory); destMesh._setGPUMemory(this.gpuMemory); var i; var boneNames = this._boneNames; if (boneNames) { var destBoneNames = destMesh._boneNames = []; for (i = 0; i < boneNames.length; i++) destBoneNames[i] = boneNames[i]; } var inverseBindPoses = this._inverseBindPoses; if (inverseBindPoses) { var destInverseBindPoses = destMesh._inverseBindPoses = []; for (i = 0; i < inverseBindPoses.length; i++) destInverseBindPoses[i] = inverseBindPoses[i]; } var cacheLength = this._skinnedMatrixCaches.length; destMesh._skinnedMatrixCaches.length = cacheLength; for (i = 0; i < cacheLength; i++) { var skinnedCache = this._skinnedMatrixCaches[i]; destMesh._skinnedMatrixCaches[i] = new skinnedMatrixCache(skinnedCache.subMeshIndex, skinnedCache.batchIndex, skinnedCache.batchBoneIndex); } for (i = 0; i < this.subMeshCount; i++) { var subMesh = this._subMeshes[i]; var subIndexBufferStart = subMesh._subIndexBufferStart; var subIndexBufferCount = subMesh._subIndexBufferCount; var boneIndicesList = subMesh._boneIndicesList; var destSubmesh = new SubMesh(destMesh); destSubmesh._subIndexBufferStart.length = subIndexBufferStart.length; destSubmesh._subIndexBufferCount.length = subIndexBufferCount.length; destSubmesh._boneIndicesList.length = boneIndicesList.length; for (var j = 0; j < subIndexBufferStart.length; j++) destSubmesh._subIndexBufferStart[j] = subIndexBufferStart[j]; for (j = 0; j < subIndexBufferCount.length; j++) destSubmesh._subIndexBufferCount[j] = subIndexBufferCount[j]; for (j = 0; j < boneIndicesList.length; j++) destSubmesh._boneIndicesList[j] = new Uint16Array(boneIndicesList[j]); destSubmesh._indexBuffer = destIB; destSubmesh._indexStart = subMesh._indexStart; destSubmesh._indexCount = subMesh._indexCount; destSubmesh._indices = new Uint16Array(destIB.getData().buffer, subMesh._indexStart * 2, subMesh._indexCount); var vertexBuffer = destMesh._vertexBuffer; destSubmesh._vertexBuffer = vertexBuffer; destMesh._subMeshes.push(destSubmesh); } destMesh._setSubMeshes(destMesh._subMeshes); } clone() { var dest = new Mesh(); this.cloneTo(dest); return dest; } } Mesh.MESH = "MESH"; class PrimitiveMesh { static __init__() { } static _createMesh(vertexDeclaration, vertices, indices) { var gl = Laya.LayaGL.instance; var mesh = new Mesh(); var subMesh = new SubMesh(mesh); var vertexBuffer = new VertexBuffer3D(vertices.length * 4, gl.STATIC_DRAW, true); vertexBuffer.vertexDeclaration = vertexDeclaration; vertexBuffer.setData(vertices.buffer); mesh._vertexBuffer = vertexBuffer; mesh._vertexCount = vertexBuffer._byteLength / vertexDeclaration.vertexStride; var indexBuffer = new IndexBuffer3D(exports.IndexFormat.UInt16, indices.length, gl.STATIC_DRAW, true); indexBuffer.setData(indices); mesh._indexBuffer = indexBuffer; mesh._setBuffer(vertexBuffer, indexBuffer); subMesh._vertexBuffer = vertexBuffer; subMesh._indexBuffer = indexBuffer; subMesh._setIndexRange(0, indexBuffer.indexCount); var subIndexBufferStart = subMesh._subIndexBufferStart; var subIndexBufferCount = subMesh._subIndexBufferCount; var boneIndicesList = subMesh._boneIndicesList; subIndexBufferStart.length = 1; subIndexBufferCount.length = 1; boneIndicesList.length = 1; subIndexBufferStart[0] = 0; subIndexBufferCount[0] = indexBuffer.indexCount; var subMeshes = []; subMeshes.push(subMesh); mesh._setSubMeshes(subMeshes); mesh.calculateBounds(); var memorySize = vertexBuffer._byteLength + indexBuffer._byteLength; mesh._setCPUMemory(memorySize); mesh._setGPUMemory(memorySize); return mesh; } static createBox(long = 1, height = 1, width = 1) { var vertexDeclaration = VertexMesh.getVertexDeclaration("POSITION,NORMAL,UV"); var halfLong = long / 2; var halfHeight = height / 2; var halfWidth = width / 2; var vertices = new Float32Array([ -halfLong, halfHeight, -halfWidth, 0, 1, 0, 0, 0, halfLong, halfHeight, -halfWidth, 0, 1, 0, 1, 0, halfLong, halfHeight, halfWidth, 0, 1, 0, 1, 1, -halfLong, halfHeight, halfWidth, 0, 1, 0, 0, 1, -halfLong, -halfHeight, -halfWidth, 0, -1, 0, 0, 1, halfLong, -halfHeight, -halfWidth, 0, -1, 0, 1, 1, halfLong, -halfHeight, halfWidth, 0, -1, 0, 1, 0, -halfLong, -halfHeight, halfWidth, 0, -1, 0, 0, 0, -halfLong, halfHeight, -halfWidth, -1, 0, 0, 0, 0, -halfLong, halfHeight, halfWidth, -1, 0, 0, 1, 0, -halfLong, -halfHeight, halfWidth, -1, 0, 0, 1, 1, -halfLong, -halfHeight, -halfWidth, -1, 0, 0, 0, 1, halfLong, halfHeight, -halfWidth, 1, 0, 0, 1, 0, halfLong, halfHeight, halfWidth, 1, 0, 0, 0, 0, halfLong, -halfHeight, halfWidth, 1, 0, 0, 0, 1, halfLong, -halfHeight, -halfWidth, 1, 0, 0, 1, 1, -halfLong, halfHeight, halfWidth, 0, 0, 1, 0, 0, halfLong, halfHeight, halfWidth, 0, 0, 1, 1, 0, halfLong, -halfHeight, halfWidth, 0, 0, 1, 1, 1, -halfLong, -halfHeight, halfWidth, 0, 0, 1, 0, 1, -halfLong, halfHeight, -halfWidth, 0, 0, -1, 1, 0, halfLong, halfHeight, -halfWidth, 0, 0, -1, 0, 0, halfLong, -halfHeight, -halfWidth, 0, 0, -1, 0, 1, -halfLong, -halfHeight, -halfWidth, 0, 0, -1, 1, 1 ]); var indices = new Uint16Array([ 0, 1, 2, 2, 3, 0, 4, 7, 6, 6, 5, 4, 8, 9, 10, 10, 11, 8, 12, 15, 14, 14, 13, 12, 16, 17, 18, 18, 19, 16, 20, 23, 22, 22, 21, 20 ]); return PrimitiveMesh._createMesh(vertexDeclaration, vertices, indices); } static createCapsule(radius = 0.5, height = 2, stacks = 16, slices = 32) { var vertexCount = (stacks + 1) * (slices + 1) * 2 + (slices + 1) * 2; var indexCount = (3 * stacks * (slices + 1)) * 2 * 2 + 2 * slices * 3; var vertexDeclaration = VertexMesh.getVertexDeclaration("POSITION,NORMAL,UV"); var vertexFloatStride = vertexDeclaration.vertexStride / 4; var vertices = new Float32Array(vertexCount * vertexFloatStride); var indices = new Uint16Array(indexCount); var stackAngle = (Math.PI / 2.0) / stacks; var sliceAngle = (Math.PI * 2.0) / slices; var hcHeight = height / 2 - radius; var posX = 0; var posY = 0; var posZ = 0; var vc = 0; var ic = 0; var verticeCount = 0; var stack, slice; for (stack = 0; stack <= stacks; stack++) { for (slice = 0; slice <= slices; slice++) { posX = radius * Math.cos(stack * stackAngle) * Math.cos(slice * sliceAngle + Math.PI); posY = radius * Math.sin(stack * stackAngle); posZ = radius * Math.cos(stack * stackAngle) * Math.sin(slice * sliceAngle + Math.PI); vertices[vc++] = posX; vertices[vc++] = posY + hcHeight; vertices[vc++] = posZ; vertices[vc++] = posX; vertices[vc++] = posY; vertices[vc++] = posZ; vertices[vc++] = 1 - slice / slices; vertices[vc++] = (1 - stack / stacks) * ((Math.PI * radius / 2) / (height + Math.PI * radius)); if (stack < stacks) { indices[ic++] = (stack * (slices + 1)) + slice + (slices + 1); indices[ic++] = (stack * (slices + 1)) + slice; indices[ic++] = (stack * (slices + 1)) + slice + 1; indices[ic++] = (stack * (slices + 1)) + slice + (slices); indices[ic++] = (stack * (slices + 1)) + slice; indices[ic++] = (stack * (slices + 1)) + slice + (slices + 1); } } } verticeCount += (stacks + 1) * (slices + 1); for (stack = 0; stack <= stacks; stack++) { for (slice = 0; slice <= slices; slice++) { posX = radius * Math.cos(stack * stackAngle) * Math.cos(slice * sliceAngle + Math.PI); posY = radius * Math.sin(-stack * stackAngle); posZ = radius * Math.cos(stack * stackAngle) * Math.sin(slice * sliceAngle + Math.PI); vertices[vc++] = posX; vertices[vc++] = posY - hcHeight; vertices[vc++] = posZ; vertices[vc++] = posX; vertices[vc++] = posY; vertices[vc++] = posZ; vertices[vc++] = 1 - slice / slices; vertices[vc++] = ((stack / stacks) * (Math.PI * radius / 2) + (height + Math.PI * radius / 2)) / (height + Math.PI * radius); if (stack < stacks) { indices[ic++] = verticeCount + (stack * (slices + 1)) + slice; indices[ic++] = verticeCount + (stack * (slices + 1)) + slice + (slices + 1); indices[ic++] = verticeCount + (stack * (slices + 1)) + slice + 1; indices[ic++] = verticeCount + (stack * (slices + 1)) + slice; indices[ic++] = verticeCount + (stack * (slices + 1)) + slice + (slices); indices[ic++] = verticeCount + (stack * (slices + 1)) + slice + (slices + 1); } } } verticeCount += (stacks + 1) * (slices + 1); for (slice = 0; slice <= slices; slice++) { posX = radius * Math.cos(slice * sliceAngle + Math.PI); posY = hcHeight; posZ = radius * Math.sin(slice * sliceAngle + Math.PI); vertices[vc++] = posX; vertices[vc + (slices + 1) * 8 - 1] = posX; vertices[vc++] = posY; vertices[vc + (slices + 1) * 8 - 1] = -posY; vertices[vc++] = posZ; vertices[vc + (slices + 1) * 8 - 1] = posZ; vertices[vc++] = posX; vertices[vc + (slices + 1) * 8 - 1] = posX; vertices[vc++] = 0; vertices[vc + (slices + 1) * 8 - 1] = 0; vertices[vc++] = posZ; vertices[vc + (slices + 1) * 8 - 1] = posZ; vertices[vc++] = 1 - slice * 1 / slices; vertices[vc + (slices + 1) * 8 - 1] = 1 - slice * 1 / slices; vertices[vc++] = (Math.PI * radius / 2) / (height + Math.PI * radius); vertices[vc + (slices + 1) * 8 - 1] = (Math.PI * radius / 2 + height) / (height + Math.PI * radius); } for (slice = 0; slice < slices; slice++) { indices[ic++] = slice + verticeCount + (slices + 1); indices[ic++] = slice + verticeCount + 1; indices[ic++] = slice + verticeCount; indices[ic++] = slice + verticeCount + (slices + 1); indices[ic++] = slice + verticeCount + (slices + 1) + 1; indices[ic++] = slice + verticeCount + 1; } verticeCount += 2 * (slices + 1); return PrimitiveMesh._createMesh(vertexDeclaration, vertices, indices); } static createCone(radius = 0.5, height = 1, slices = 32) { var vertexCount = (slices + 1 + 1) + (slices + 1) * 2; var indexCount = 6 * slices + 3 * slices; var vertexDeclaration = VertexMesh.getVertexDeclaration("POSITION,NORMAL,UV"); var vertexFloatStride = vertexDeclaration.vertexStride / 4; var vertices = new Float32Array(vertexCount * vertexFloatStride); var indices = new Uint16Array(indexCount); var sliceAngle = (Math.PI * 2.0) / slices; var halfHeight = height / 2; var curAngle = 0; var verticeCount = 0; var posX = 0; var posY = 0; var posZ = 0; var normal = new Vector3(); var downV3 = new Vector3(0, -1, 0); var upPoint = new Vector3(0, halfHeight, 0); var downPoint = new Vector3(); var v3 = new Vector3(); var q4 = new Quaternion(); var rotateAxis = new Vector3(); var rotateRadius; var vc = 0; var ic = 0; for (var rv = 0; rv <= slices; rv++) { curAngle = rv * sliceAngle; posX = Math.cos(curAngle + Math.PI) * radius; posY = halfHeight; posZ = Math.sin(curAngle + Math.PI) * radius; vertices[vc++] = 0; vertices[vc + (slices + 1) * 8 - 1] = posX; vertices[vc++] = posY; vertices[vc + (slices + 1) * 8 - 1] = -posY; vertices[vc++] = 0; vertices[vc + (slices + 1) * 8 - 1] = posZ; normal.x = posX; normal.y = 0; normal.z = posZ; downPoint.x = posX; downPoint.y = -posY; downPoint.z = posZ; Vector3.subtract(downPoint, upPoint, v3); Vector3.normalize(v3, v3); rotateRadius = Math.acos(Vector3.dot(downV3, v3)); Vector3.cross(downV3, v3, rotateAxis); Vector3.normalize(rotateAxis, rotateAxis); Quaternion.createFromAxisAngle(rotateAxis, rotateRadius, q4); Vector3.normalize(normal, normal); Vector3.transformQuat(normal, q4, normal); Vector3.normalize(normal, normal); vertices[vc++] = normal.x; vertices[vc + (slices + 1) * 8 - 1] = normal.x; vertices[vc++] = normal.y; vertices[vc + (slices + 1) * 8 - 1] = normal.y; vertices[vc++] = normal.z; vertices[vc + (slices + 1) * 8 - 1] = normal.z; vertices[vc++] = 1 - rv * 1 / slices; vertices[vc + (slices + 1) * 8 - 1] = 1 - rv * 1 / slices; vertices[vc++] = 0; vertices[vc + (slices + 1) * 8 - 1] = 1; } vc += (slices + 1) * 8; for (var ri = 0; ri < slices; ri++) { indices[ic++] = ri + verticeCount + (slices + 1); indices[ic++] = ri + verticeCount + 1; indices[ic++] = ri + verticeCount; indices[ic++] = ri + verticeCount + (slices + 1); indices[ic++] = ri + verticeCount + (slices + 1) + 1; indices[ic++] = ri + verticeCount + 1; } verticeCount += 2 * (slices + 1); for (var bv = 0; bv <= slices; bv++) { if (bv === 0) { vertices[vc++] = 0; vertices[vc++] = -halfHeight; vertices[vc++] = 0; vertices[vc++] = 0; vertices[vc++] = -1; vertices[vc++] = 0; vertices[vc++] = 0.5; vertices[vc++] = 0.5; } curAngle = bv * sliceAngle; posX = Math.cos(curAngle + Math.PI) * radius; posY = -halfHeight; posZ = Math.sin(curAngle + Math.PI) * radius; vertices[vc++] = posX; vertices[vc++] = posY; vertices[vc++] = posZ; vertices[vc++] = 0; vertices[vc++] = -1; vertices[vc++] = 0; vertices[vc++] = 0.5 + Math.cos(curAngle) * 0.5; vertices[vc++] = 0.5 + Math.sin(curAngle) * 0.5; } for (var bi = 0; bi < slices; bi++) { indices[ic++] = 0 + verticeCount; indices[ic++] = bi + 2 + verticeCount; indices[ic++] = bi + 1 + verticeCount; } verticeCount += slices + 1 + 1; return PrimitiveMesh._createMesh(vertexDeclaration, vertices, indices); } static createCylinder(radius = 0.5, height = 2, slices = 32) { var vertexCount = (slices + 1 + 1) + (slices + 1) * 2 + (slices + 1 + 1); var indexCount = 3 * slices + 6 * slices + 3 * slices; var vertexDeclaration = VertexMesh.getVertexDeclaration("POSITION,NORMAL,UV"); var vertexFloatStride = vertexDeclaration.vertexStride / 4; var vertices = new Float32Array(vertexCount * vertexFloatStride); var indices = new Uint16Array(indexCount); var sliceAngle = (Math.PI * 2.0) / slices; var halfHeight = height / 2; var curAngle = 0; var verticeCount = 0; var posX = 0; var posY = 0; var posZ = 0; var vc = 0; var ic = 0; for (var tv = 0; tv <= slices; tv++) { if (tv === 0) { vertices[vc++] = 0; vertices[vc++] = halfHeight; vertices[vc++] = 0; vertices[vc++] = 0; vertices[vc++] = 1; vertices[vc++] = 0; vertices[vc++] = 0.5; vertices[vc++] = 0.5; } curAngle = tv * sliceAngle; posX = Math.cos(curAngle) * radius; posY = halfHeight; posZ = Math.sin(curAngle) * radius; vertices[vc++] = posX; vertices[vc++] = posY; vertices[vc++] = posZ; vertices[vc++] = 0; vertices[vc++] = 1; vertices[vc++] = 0; vertices[vc++] = 0.5 + Math.cos(curAngle) * 0.5; vertices[vc++] = 0.5 + Math.sin(curAngle) * 0.5; } for (var ti = 0; ti < slices; ti++) { indices[ic++] = 0; indices[ic++] = ti + 1; indices[ic++] = ti + 2; } verticeCount += slices + 1 + 1; for (var rv = 0; rv <= slices; rv++) { curAngle = rv * sliceAngle; posX = Math.cos(curAngle + Math.PI) * radius; posY = halfHeight; posZ = Math.sin(curAngle + Math.PI) * radius; vertices[vc++] = posX; vertices[vc + (slices + 1) * 8 - 1] = posX; vertices[vc++] = posY; vertices[vc + (slices + 1) * 8 - 1] = -posY; vertices[vc++] = posZ; vertices[vc + (slices + 1) * 8 - 1] = posZ; vertices[vc++] = posX; vertices[vc + (slices + 1) * 8 - 1] = posX; vertices[vc++] = 0; vertices[vc + (slices + 1) * 8 - 1] = 0; vertices[vc++] = posZ; vertices[vc + (slices + 1) * 8 - 1] = posZ; vertices[vc++] = 1 - rv * 1 / slices; vertices[vc + (slices + 1) * 8 - 1] = 1 - rv * 1 / slices; vertices[vc++] = 0; vertices[vc + (slices + 1) * 8 - 1] = 1; } vc += (slices + 1) * 8; for (var ri = 0; ri < slices; ri++) { indices[ic++] = ri + verticeCount + (slices + 1); indices[ic++] = ri + verticeCount + 1; indices[ic++] = ri + verticeCount; indices[ic++] = ri + verticeCount + (slices + 1); indices[ic++] = ri + verticeCount + (slices + 1) + 1; indices[ic++] = ri + verticeCount + 1; } verticeCount += 2 * (slices + 1); for (var bv = 0; bv <= slices; bv++) { if (bv === 0) { vertices[vc++] = 0; vertices[vc++] = -halfHeight; vertices[vc++] = 0; vertices[vc++] = 0; vertices[vc++] = -1; vertices[vc++] = 0; vertices[vc++] = 0.5; vertices[vc++] = 0.5; } curAngle = bv * sliceAngle; posX = Math.cos(curAngle + Math.PI) * radius; posY = -halfHeight; posZ = Math.sin(curAngle + Math.PI) * radius; vertices[vc++] = posX; vertices[vc++] = posY; vertices[vc++] = posZ; vertices[vc++] = 0; vertices[vc++] = -1; vertices[vc++] = 0; vertices[vc++] = 0.5 + Math.cos(curAngle) * 0.5; vertices[vc++] = 0.5 + Math.sin(curAngle) * 0.5; } for (var bi = 0; bi < slices; bi++) { indices[ic++] = 0 + verticeCount; indices[ic++] = bi + 2 + verticeCount; indices[ic++] = bi + 1 + verticeCount; } verticeCount += slices + 1 + 1; return PrimitiveMesh._createMesh(vertexDeclaration, vertices, indices); } static createPlane(long = 10, width = 10, stacks = 10, slices = 10) { var vertexCount = (stacks + 1) * (slices + 1); var indexCount = stacks * slices * 2 * 3; var indices = new Uint16Array(indexCount); var vertexDeclaration = VertexMesh.getVertexDeclaration("POSITION,NORMAL,UV"); var vertexFloatStride = vertexDeclaration.vertexStride / 4; var vertices = new Float32Array(vertexCount * vertexFloatStride); var halfLong = long / 2; var halfWidth = width / 2; var stacksLong = long / stacks; var slicesWidth = width / slices; var verticeCount = 0; for (var i = 0; i <= slices; i++) { for (var j = 0; j <= stacks; j++) { vertices[verticeCount++] = j * stacksLong - halfLong; vertices[verticeCount++] = 0; vertices[verticeCount++] = i * slicesWidth - halfWidth; vertices[verticeCount++] = 0; vertices[verticeCount++] = 1; vertices[verticeCount++] = 0; vertices[verticeCount++] = j * 1 / stacks; vertices[verticeCount++] = i * 1 / slices; } } var indiceIndex = 0; for (i = 0; i < slices; i++) { for (j = 0; j < stacks; j++) { indices[indiceIndex++] = (i + 1) * (stacks + 1) + j; indices[indiceIndex++] = i * (stacks + 1) + j; indices[indiceIndex++] = (i + 1) * (stacks + 1) + j + 1; indices[indiceIndex++] = i * (stacks + 1) + j; indices[indiceIndex++] = i * (stacks + 1) + j + 1; indices[indiceIndex++] = (i + 1) * (stacks + 1) + j + 1; } } return PrimitiveMesh._createMesh(vertexDeclaration, vertices, indices); } static createQuad(long = 1, width = 1) { var vertexDeclaration = VertexMesh.getVertexDeclaration("POSITION,NORMAL,UV"); var halfLong = long / 2; var halfWidth = width / 2; var vertices = new Float32Array([-halfLong, halfWidth, 0, 0, 0, 1, 0, 0, halfLong, halfWidth, 0, 0, 0, 1, 1, 0, -halfLong, -halfWidth, 0, 0, 0, 1, 0, 1, halfLong, -halfWidth, 0, 0, 0, 1, 1, 1]); var indices = new Uint16Array([0, 1, 2, 3, 2, 1]); return PrimitiveMesh._createMesh(vertexDeclaration, vertices, indices); } static createSphere(radius = 0.5, stacks = 32, slices = 32) { var vertexCount = (stacks + 1) * (slices + 1); var indexCount = (3 * stacks * (slices + 1)) * 2; var indices = new Uint16Array(indexCount); var vertexDeclaration = VertexMesh.getVertexDeclaration("POSITION,NORMAL,UV"); var vertexFloatStride = vertexDeclaration.vertexStride / 4; var vertices = new Float32Array(vertexCount * vertexFloatStride); var stackAngle = Math.PI / stacks; var sliceAngle = (Math.PI * 2.0) / slices; var vertexIndex = 0; vertexCount = 0; indexCount = 0; for (var stack = 0; stack < (stacks + 1); stack++) { var r = Math.sin(stack * stackAngle); var y = Math.cos(stack * stackAngle); for (var slice = 0; slice < (slices + 1); slice++) { var x = r * Math.sin(slice * sliceAngle + Math.PI * 1 / 2); var z = r * Math.cos(slice * sliceAngle + Math.PI * 1 / 2); vertices[vertexCount + 0] = x * radius; vertices[vertexCount + 1] = y * radius; vertices[vertexCount + 2] = z * radius; vertices[vertexCount + 3] = x; vertices[vertexCount + 4] = y; vertices[vertexCount + 5] = z; vertices[vertexCount + 6] = slice / slices; vertices[vertexCount + 7] = stack / stacks; vertexCount += vertexFloatStride; if (stack != (stacks - 1)) { indices[indexCount++] = vertexIndex + (slices + 1); indices[indexCount++] = vertexIndex; indices[indexCount++] = vertexIndex + 1; indices[indexCount++] = vertexIndex + (slices); indices[indexCount++] = vertexIndex; indices[indexCount++] = vertexIndex + (slices + 1); vertexIndex++; } } } return PrimitiveMesh._createMesh(vertexDeclaration, vertices, indices); } } var BlitScreenPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\nuniform sampler2D u_MainTex;\r\nvarying vec2 v_Texcoord0;\r\n\r\nvoid main() {\r\n\tgl_FragColor = texture2D(u_MainTex, v_Texcoord0);\r\n}\r\n\r\n"; var BlitScreenVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_PositionTexcoord;\r\nuniform vec4 u_OffsetScale;\r\nvarying vec2 v_Texcoord0;\r\n\r\nvoid main() {\t\r\n\tgl_Position = vec4(u_OffsetScale.x*2.0-1.0+(a_PositionTexcoord.x+1.0)*u_OffsetScale.z,(1.0-((u_OffsetScale.y*2.0-1.0+(-a_PositionTexcoord.y+1.0)*u_OffsetScale.w)+1.0)/2.0)*2.0-1.0, 0.0, 1.0);\t\r\n\tv_Texcoord0 = a_PositionTexcoord.zw;\r\n\tgl_Position = remapGLPositionZ(gl_Position);\r\n}"; var EffectPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#ifdef COLOR\r\n\tvarying vec4 v_Color;\r\n#endif\r\nvarying vec2 v_Texcoord0;\r\n\r\n#ifdef MAINTEXTURE\r\n\tuniform sampler2D u_AlbedoTexture;\r\n#endif\r\n\r\nuniform vec4 u_AlbedoColor;\r\n\r\n#ifdef FOG\r\n\tuniform float u_FogStart;\r\n\tuniform float u_FogRange;\r\n\t#ifdef ADDTIVEFOG\r\n\t#else\r\n\t\tuniform vec3 u_FogColor;\r\n\t#endif\r\n#endif\r\n\r\nvoid main()\r\n{\r\n\tvec4 color = 2.0 * u_AlbedoColor;\r\n\t#ifdef COLOR\r\n\t\tcolor *= v_Color;\r\n\t#endif\r\n\t#ifdef MAINTEXTURE\r\n\t\tcolor *= texture2D(u_AlbedoTexture, v_Texcoord0);\r\n\t#endif\r\n\t\r\n\tgl_FragColor = color;\r\n\t\r\n\t#ifdef FOG\r\n\t\tfloat lerpFact = clamp((1.0 / gl_FragCoord.w - u_FogStart) / u_FogRange, 0.0, 1.0);\r\n\t\t#ifdef ADDTIVEFOG\r\n\t\t\tgl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.0), lerpFact);\r\n\t\t#else\r\n\t\t\tgl_FragColor.rgb = mix(gl_FragColor.rgb, u_FogColor, lerpFact);\r\n\t\t#endif\r\n\t#endif\r\n}\r\n\r\n"; var EffectVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_Position;\r\nattribute vec4 a_Color;\r\nattribute vec2 a_Texcoord0;\r\n\r\n#ifdef GPU_INSTANCE\r\n\tattribute mat4 a_MvpMatrix;\r\n#else\r\n\tuniform mat4 u_MvpMatrix;\r\n#endif\r\n\r\n#ifdef COLOR\r\n\tvarying vec4 v_Color;\r\n#endif\r\nvarying vec2 v_Texcoord0;\r\n\r\n#ifdef TILINGOFFSET\r\n\tuniform vec4 u_TilingOffset;\r\n#endif\r\n\r\n#ifdef BONE\r\n\tconst int c_MaxBoneCount = 24;\r\n\tattribute vec4 a_BoneIndices;\r\n\tattribute vec4 a_BoneWeights;\r\n\tuniform mat4 u_Bones[c_MaxBoneCount];\r\n#endif\r\n\r\nvoid main()\r\n{\r\n\tvec4 position;\r\n\t#ifdef BONE\r\n\t\tmat4 skinTransform = u_Bones[int(a_BoneIndices.x)] * a_BoneWeights.x;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.y)] * a_BoneWeights.y;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.z)] * a_BoneWeights.z;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.w)] * a_BoneWeights.w;\r\n\t\tposition=skinTransform*a_Position;\r\n\t#else\r\n\t\tposition=a_Position;\r\n\t#endif\r\n\t#ifdef GPU_INSTANCE\r\n\t\tgl_Position = a_MvpMatrix * position;\r\n\t#else\r\n\t\tgl_Position = u_MvpMatrix * position;\r\n\t#endif\r\n\t\r\n\t#ifdef TILINGOFFSET\r\n\t\tv_Texcoord0=TransformUV(a_Texcoord0,u_TilingOffset);\r\n\t#else\r\n\t\tv_Texcoord0=a_Texcoord0;\r\n\t#endif\r\n\t\t\r\n\t#ifdef COLOR\r\n\t\tv_Color = a_Color;\r\n\t#endif\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}"; var extendTerrainPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Lighting.glsl\";\r\n\r\n#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)||defined(FOG)\r\n\tuniform vec3 u_CameraPos;\r\n\tvarying vec3 v_Normal;\r\n\tvarying vec3 v_PositionWorld;\r\n#endif\r\n\r\n#ifdef FOG\r\n\tuniform float u_FogStart;\r\n\tuniform float u_FogRange;\r\n\tuniform vec3 u_FogColor;\r\n#endif\r\n\r\n#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t#ifdef LEGACYSINGLELIGHTING\r\n\t\t#ifdef DIRECTIONLIGHT\r\n\t\t\tuniform DirectionLight u_DirectionLight;\r\n\t\t#endif\r\n\t\t#ifdef POINTLIGHT\r\n\t\t\tuniform PointLight u_PointLight;\r\n\t\t#endif\r\n\t\t#ifdef SPOTLIGHT\r\n\t\t\tuniform SpotLight u_SpotLight;\r\n\t\t#endif\r\n\t#else\r\n\t\tuniform mat4 u_View;\r\n\t\tuniform vec4 u_ProjectionParams;\r\n\t\tuniform vec4 u_Viewport;\r\n\t\tuniform int u_DirationLightCount;\r\n\t\tuniform sampler2D u_LightBuffer;\r\n\t\tuniform sampler2D u_LightClusterBuffer;\r\n\t#endif\r\n#endif\r\n\r\n#include \"Shadow.glsl\"\r\n#ifdef CALCULATE_SHADOWS\r\n\tvarying vec4 v_ShadowCoord;\r\n#endif\r\nvarying float v_posViewZ;\r\n\r\nuniform vec3 u_AmbientColor;\r\n\r\nuniform sampler2D u_SplatAlphaTexture;\r\n\r\nuniform sampler2D u_DiffuseTexture1;\r\nuniform sampler2D u_DiffuseTexture2;\r\nuniform sampler2D u_DiffuseTexture3;\r\nuniform sampler2D u_DiffuseTexture4;\r\nuniform sampler2D u_DiffuseTexture5;\r\n\r\nuniform vec4 u_DiffuseScaleOffset1;\r\nuniform vec4 u_DiffuseScaleOffset2;\r\nuniform vec4 u_DiffuseScaleOffset3;\r\nuniform vec4 u_DiffuseScaleOffset4;\r\nuniform vec4 u_DiffuseScaleOffset5;\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\n#ifdef LIGHTMAP\r\n\tuniform sampler2D u_LightMap;\r\n\tvarying vec2 v_LightMapUV;\r\n#endif\r\n\r\nvoid main()\r\n{\r\n\tvec4 splatAlpha = vec4(1.0);\r\n\t#ifdef ExtendTerrain_DETAIL_NUM1\r\n\t\tsplatAlpha = texture2D(u_SplatAlphaTexture, v_Texcoord0);\r\n\t\tvec4 color1 = texture2D(u_DiffuseTexture1, v_Texcoord0 * u_DiffuseScaleOffset1.xy);\r\n\t\tgl_FragColor.xyz = color1.xyz * splatAlpha.r;\r\n\t#endif\r\n\t#ifdef ExtendTerrain_DETAIL_NUM2\r\n\t\tsplatAlpha = texture2D(u_SplatAlphaTexture, v_Texcoord0);\r\n\t\tvec4 color1 = texture2D(u_DiffuseTexture1, v_Texcoord0 * u_DiffuseScaleOffset1.xy);\r\n\t\tvec4 color2 = texture2D(u_DiffuseTexture2, v_Texcoord0 * u_DiffuseScaleOffset2.xy);\r\n\t\tgl_FragColor.xyz = color1.xyz * splatAlpha.r + color2.xyz * (1.0 - splatAlpha.r);\r\n\t#endif\r\n\t#ifdef ExtendTerrain_DETAIL_NUM3\r\n\t\tsplatAlpha = texture2D(u_SplatAlphaTexture, v_Texcoord0);\r\n\t\tvec4 color1 = texture2D(u_DiffuseTexture1, v_Texcoord0 * u_DiffuseScaleOffset1.xy);\r\n\t\tvec4 color2 = texture2D(u_DiffuseTexture2, v_Texcoord0 * u_DiffuseScaleOffset2.xy);\r\n\t\tvec4 color3 = texture2D(u_DiffuseTexture3, v_Texcoord0 * u_DiffuseScaleOffset3.xy);\r\n\t\tgl_FragColor.xyz = color1.xyz * splatAlpha.r + color2.xyz * splatAlpha.g + color3.xyz * (1.0 - splatAlpha.r - splatAlpha.g);\r\n\t#endif\r\n\t#ifdef ExtendTerrain_DETAIL_NUM4\r\n\t\tsplatAlpha = texture2D(u_SplatAlphaTexture, v_Texcoord0);\r\n\t\tvec4 color1 = texture2D(u_DiffuseTexture1, v_Texcoord0 * u_DiffuseScaleOffset1.xy);\r\n\t\tvec4 color2 = texture2D(u_DiffuseTexture2, v_Texcoord0 * u_DiffuseScaleOffset2.xy);\r\n\t\tvec4 color3 = texture2D(u_DiffuseTexture3, v_Texcoord0 * u_DiffuseScaleOffset3.xy);\r\n\t\tvec4 color4 = texture2D(u_DiffuseTexture4, v_Texcoord0 * u_DiffuseScaleOffset4.xy);\r\n\t\tgl_FragColor.xyz = color1.xyz * splatAlpha.r + color2.xyz * splatAlpha.g + color3.xyz * splatAlpha.b + color4.xyz * (1.0 - splatAlpha.r - splatAlpha.g - splatAlpha.b);\r\n\t#endif\r\n\t#ifdef ExtendTerrain_DETAIL_NUM5\r\n\t\tsplatAlpha = texture2D(u_SplatAlphaTexture, v_Texcoord0);\r\n\t\tvec4 color1 = texture2D(u_DiffuseTexture1, v_Texcoord0 * u_DiffuseScaleOffset1.xy);\r\n\t\tvec4 color2 = texture2D(u_DiffuseTexture2, v_Texcoord0 * u_DiffuseScaleOffset2.xy);\r\n\t\tvec4 color3 = texture2D(u_DiffuseTexture3, v_Texcoord0 * u_DiffuseScaleOffset3.xy);\r\n\t\tvec4 color4 = texture2D(u_DiffuseTexture4, v_Texcoord0 * u_DiffuseScaleOffset4.xy);\r\n\t\tvec4 color5 = texture2D(u_DiffuseTexture5, v_Texcoord0 * u_DiffuseScaleOffset5.xy);\r\n\t\tgl_FragColor.xyz = color1.xyz * splatAlpha.r + color2.xyz * splatAlpha.g + color3.xyz * splatAlpha.b + color4.xyz * splatAlpha.a + color5.xyz * (1.0 - splatAlpha.r - splatAlpha.g - splatAlpha.b - splatAlpha.a);\r\n\t#endif\r\n\t\tgl_FragColor.w = splatAlpha.a;\r\n\t\t\r\n\t#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t\tvec3 normal = v_Normal;\r\n\t\tvec3 dif, spe;\r\n\t#endif\r\n\r\n\tvec3 diffuse = vec3(0.0);\r\n\tvec3 specular= vec3(0.0);\r\n\t#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)||defined(FOG)\r\n\t\tvec3 toEye;\r\n\t\t#ifdef FOG\r\n\t\t\ttoEye=u_CameraPos-v_PositionWorld;\r\n\t\t\tfloat toEyeLength=length(toEye);\r\n\t\t\ttoEye/=toEyeLength;\r\n\t\t#else\r\n\t\t\ttoEye=normalize(u_CameraPos-v_PositionWorld);\r\n\t\t#endif\r\n\t#endif\r\n\r\n\t#ifdef LEGACYSINGLELIGHTING\r\n\t\t#ifdef DIRECTIONLIGHT\r\n\t\t\tLayaAirBlinnPhongDiectionLight(vec3(0.0),1.0,normal,vec3(1.0),toEye,u_DirectionLight,dif,spe);\r\n\t\t\tdiffuse+=dif;\r\n\t\t\tspecular+=spe;\r\n\t\t#endif\r\n\t\r\n\t\t#ifdef POINTLIGHT\r\n\t\t\tLayaAirBlinnPhongPointLight(v_PositionWorld,vec3(0.0),1.0,normal,vec3(1.0),toEye,u_PointLight,dif,spe);\r\n\t\t\tdiffuse+=dif;\r\n\t\t\tspecular+=spe;\r\n\t\t#endif\r\n\r\n\t\t#ifdef SPOTLIGHT\r\n\t\t\tLayaAirBlinnPhongSpotLight(v_PositionWorld,vec3(0.0),1.0,normal,vec3(1.0),toEye,u_SpotLight,dif,spe);\r\n\t\t\tdiffuse+=dif;\r\n\t\t\tspecular+=spe;\r\n\t\t#endif\r\n\t#else\r\n\t\t#ifdef DIRECTIONLIGHT\r\n\t\t\tfor (int i = 0; i < MAX_LIGHT_COUNT; i++) \r\n\t\t\t{\r\n\t\t\t\tif(i >= u_DirationLightCount)\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tDirectionLight directionLight = getDirectionLight(u_LightBuffer,i);\r\n\t\t\t\tLayaAirBlinnPhongDiectionLight(vec3(0.0),1.0,normal,vec3(1.0),toEye,directionLight,dif,spe);\r\n\t\t\t\tdiffuse+=dif;\r\n\t\t\t\tspecular+=spe;\r\n\t\t\t}\r\n\t\t#endif\r\n\t\t#if defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t\t\tivec4 clusterInfo =getClusterInfo(u_LightClusterBuffer,u_View,u_Viewport, v_PositionWorld,gl_FragCoord,u_ProjectionParams);\r\n\t\t\t#ifdef POINTLIGHT\r\n\t\t\t\tfor (int i = 0; i < MAX_LIGHT_COUNT; i++) \r\n\t\t\t\t{\r\n\t\t\t\t\tif(i >= clusterInfo.x)//PointLightCount\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tPointLight pointLight = getPointLight(u_LightBuffer,u_LightClusterBuffer,clusterInfo,i);\r\n\t\t\t\t\tLayaAirBlinnPhongPointLight(v_PositionWorld,vec3(0.0),1.0,normal,vec3(1.0),toEye,pointLight,dif,spe);\r\n\t\t\t\t\tdiffuse+=dif;\r\n\t\t\t\t\tspecular+=spe;\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t\t#ifdef SPOTLIGHT\r\n\t\t\t\tfor (int i = 0; i < MAX_LIGHT_COUNT; i++) \r\n\t\t\t\t{\r\n\t\t\t\t\tif(i >= clusterInfo.y)//SpotLightCount\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tSpotLight spotLight = getSpotLight(u_LightBuffer,u_LightClusterBuffer,clusterInfo,i);\r\n\t\t\t\t\tLayaAirBlinnPhongSpotLight(v_PositionWorld,vec3(0.0),1.0,normal,vec3(1.0),toEye\t,spotLight,dif,spe);\r\n\t\t\t\t\tdiffuse+=dif;\r\n\t\t\t\t\tspecular+=spe;\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t#endif\r\n\t#endif\r\n\r\nvec3 globalDiffuse = u_AmbientColor;\r\n#ifdef LIGHTMAP\r\n\tglobalDiffuse += decodeHDR(texture2D(u_LightMap, v_LightMapUV),5.0);\r\n#endif\r\n\r\n#ifdef CALCULATE_SHADOWS\r\n\tfloat shadowValue = shadowValue = sampleShadowmap(v_ShadowCoord);\r\n\tgl_FragColor = vec4(gl_FragColor.rgb * (globalDiffuse + diffuse) * shadowValue, gl_FragColor.a);\r\n#else\r\n\tgl_FragColor = vec4(gl_FragColor.rgb * (globalDiffuse + diffuse), gl_FragColor.a);\r\n#endif\r\n\r\n#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t#ifdef CALCULATE_SHADOWS\r\n\t\tgl_FragColor.rgb += specular * shadowValue;\r\n\t#else\r\n\t\tgl_FragColor.rgb += specular;\r\n\t#endif\r\n#endif\r\n\r\n#ifdef FOG\r\n\tfloat lerpFact=clamp((toEyeLength-u_FogStart)/u_FogRange,0.0,1.0);\r\n\tgl_FragColor.rgb=mix(gl_FragColor.rgb,u_FogColor,lerpFact);\r\n#endif\r\n}\r\n\r\n\r\n\r\n\r\n\r\n"; var extendTerrainVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_Position;\r\nattribute vec2 a_Texcoord0;\r\n\r\nuniform mat4 u_MvpMatrix;\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\n#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)||defined(LIGHTMAP)\r\n\tattribute vec3 a_Normal;\r\n\tvarying vec3 v_Normal;\r\n#endif\r\n\r\n#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)||defined(FOG)||(defined(CALCULATE_SHADOWS)&&defined(SHADOWMAP_PSSM1))\r\n\tuniform mat4 u_WorldMat;\r\n\tvarying vec3 v_PositionWorld;\r\n#endif\r\n\r\n#ifdef LIGHTMAP\r\n\tvarying vec2 v_LightMapUV;\r\n\tuniform vec4 u_LightmapScaleOffset;\r\n#endif\r\n\r\n#ifdef CALCULATE_SHADOWS\r\n\tvarying vec4 v_ShadowCoord;\r\n#endif\r\n\r\nvoid main()\r\n{\r\n\tgl_Position = u_MvpMatrix * a_Position;\r\n \r\n\tv_Texcoord0 = a_Texcoord0;\r\n \r\n\t#ifdef LIGHTMAP\r\n\t\tv_LightMapUV = vec2(a_Texcoord0.x, 1.0 - a_Texcoord0.y) * u_LightmapScaleOffset.xy + u_LightmapScaleOffset.zw;\r\n\t\tv_LightMapUV.y = 1.0 - v_LightMapUV.y;\r\n\t#endif\r\n \r\n\t#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t\tv_Normal = a_Normal;\r\n\t#endif\r\n\r\n\t#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)||defined(FOG)||(defined(CALCULATE_SHADOWS)&&defined(SHADOWMAP_PSSM1))\r\n\t\tv_PositionWorld=(u_WorldMat*a_Position).xyz;\r\n\t#endif\r\n\r\n\t#ifdef CALCULATE_SHADOWS\r\n\t\tv_ShadowCoord = getShadowCoord(vec4(v_PositionWorld));\r\n\t#endif\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}"; var GlobalIllumination = "struct LayaGIInput\r\n{\r\n\tvec2 lightmapUV;\r\n};\r\n\r\n#define LAYA_SPECCUBE_LOD_STEPS 6.0\r\n\r\nuniform vec3 u_AmbientColor;\r\n\r\n#if defined(GI_AMBIENT_SH)\r\n\tuniform vec4 u_AmbientSHAr;\r\n\tuniform vec4 u_AmbientSHAg;\r\n\tuniform vec4 u_AmbientSHAb;\r\n\tuniform vec4 u_AmbientSHBr;\r\n\tuniform vec4 u_AmbientSHBg;\r\n\tuniform vec4 u_AmbientSHBb;\r\n\tuniform vec4 u_AmbientSHC;\r\n#endif\r\n\r\nuniform samplerCube u_ReflectTexture;\r\nuniform vec4 u_ReflectCubeHDRParams;\r\n\r\n\r\n#ifdef GI_AMBIENT_SH\r\n\tmediump vec3 shEvalLinearL0L1(mediump vec4 normal)\r\n\t{\r\n\t\tmediump vec3 x;\r\n\t\t// Linear (L1) + constant (L0) polynomial terms\r\n\t\tx.r = dot(u_AmbientSHAr, normal);\r\n\t\tx.g = dot(u_AmbientSHAg, normal);\r\n\t\tx.b = dot(u_AmbientSHAb, normal);\r\n\t\treturn x;\r\n\t}\r\n\r\n\tmediump vec3 shEvalLinearL2(mediump vec4 normal)\r\n\t{\r\n\t\tmediump vec3 x1,x2;\r\n\t\t// 4 of the quadratic (L2) polynomials\r\n\t\tmediump vec4 vB = normal.xyzz * normal.yzzx;\r\n\t\tx1.r = dot(u_AmbientSHBr, vB);\r\n\t\tx1.g = dot(u_AmbientSHBg, vB);\r\n\t\tx1.b = dot(u_AmbientSHBb, vB);\r\n\r\n\t\t// Final (5th) quadratic (L2) polynomial\r\n\t\tmediump float vC = normal.x*normal.x - normal.y*normal.y;\r\n\t\tx2 = u_AmbientSHC.rgb * vC;\r\n\r\n\t\treturn x1 + x2;\r\n\t}\r\n\t\r\n\tmediump vec3 shadeSHPerPixel(mediump vec3 normal)\r\n\t{\r\n\t\tmediump vec3 ambientContrib;\r\n\t\tmediump vec4 normalV4=vec4(-normal.x,normal.yz, 1.0);//Note:SH Data is left-hand,so x need inverse\r\n\t\tambientContrib = shEvalLinearL0L1(normalV4);\r\n\t\tambientContrib += shEvalLinearL2(normalV4);\r\n\t\tmediump vec3 ambient = max(vec3(0.0), ambientContrib);\r\n\t\tambient = layaLinearToGammaSpace(ambient);\r\n\t\treturn ambient;\r\n\t}\r\n#endif\r\n\r\nmediump vec3 layaDecodeDirectionalLightmap (mediump vec3 color, lowp vec4 dirTex, mediump vec3 normalWorld)\r\n{\r\n // In directional (non-specular) mode Enlighten bakes dominant light direction\r\n // in a way, that using it for half Lambert and then dividing by a \"rebalancing coefficient\"\r\n // gives a result close to plain diffuse response lightmaps, but normalmapped.\r\n\r\n // Note that dir is not unit length on purpose. Its length is \"directionality\", like\r\n // for the directional specular lightmaps.\r\n\tlowp vec3 directional=dirTex.xyz - 0.5;\r\n\tdirectional.x=-directional.x;//NOTE:because coord System\r\n mediump float halfLambert = dot(normalWorld,directional) + 0.5;\r\n\r\n return color * halfLambert / max(1e-4, dirTex.w);\r\n}\r\n\r\nvec3 layaGIBase(LayaGIInput giInput,mediump float occlusion, mediump vec3 normalWorld)\r\n{\r\n\tvec3 indirectDiffuse;\r\n\t#ifdef LIGHTMAP\t\r\n\t\tmediump vec3 bakedColor =decodeHDR(texture2D(u_LightMap, giInput.lightmapUV),5.0);\r\n\t\t#ifdef LIGHTMAP_DIRECTIONAL\r\n\t\t\tlowp vec4 bakedDirTex = texture2D (u_LightMapDirection, giInput.lightmapUV);\r\n indirectDiffuse = layaDecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);\r\n\t\t#else //unDirectional lightmap\r\n\t\t\tindirectDiffuse = bakedColor;\r\n\t\t#endif\r\n\t#else\r\n\t\t#ifdef GI_AMBIENT_SH\r\n\t\t\tindirectDiffuse = shadeSHPerPixel(normalWorld);\r\n\t\t#else\r\n\t\t\tindirectDiffuse = u_AmbientColor; //already in gamma space\r\n\t\t#endif\r\n\t#endif\r\n\r\n\tindirectDiffuse*=occlusion;\r\n\treturn indirectDiffuse;\r\n}\r\n\r\nmediump vec3 layaGlossyEnvironment(mediump vec4 glossIn)\r\n{\r\n\tmediump float perceptualRoughness = glossIn.a;\r\n\r\n\t// use approximation to solve,below is more reasonable,but maybe slow. \r\n\t// float m = perceptualRoughnessToRoughness(perceptualRoughness); // m is the real roughness parameter\r\n // const float fEps = 1.192092896e-07F; // smallest such that 1.0+FLT_EPSILON != 1.0 (+1e-4h is NOT good here. is visibly very wrong)\r\n // float n = (2.0/max(fEps, m*m))-2.0; // remap to spec power. See eq. 21 in --> https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf\r\n // n /= 4; // remap from n_dot_h formulatino to n_dot_r. See section \"Pre-convolved Cube Maps vs Path Tracers\" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html\r\n // perceptualRoughness = pow( 2/(n+2), 0.25); // remap back to square root of real roughness (0.25 include both the sqrt root of the conversion and sqrt for going from roughness to perceptualRoughness)\r\n\tperceptualRoughness = perceptualRoughness * (1.7 - 0.7*perceptualRoughness);//just a approximation,but fast.\r\n \r\n\tmediump float mip = perceptualRoughness * LAYA_SPECCUBE_LOD_STEPS;\r\n\tmediump vec3 uvw = glossIn.rgb;\r\n\tuvw.x=-uvw.x;//Note:reflectCube is left-hand,so x need inverse\r\n\tmediump vec4 rgbm=textureCubeLodEXT(u_ReflectTexture,uvw,mip);\r\n\treturn decodeHDR(rgbm,u_ReflectCubeHDRParams.x);\r\n}\r\n\r\nmediump vec3 layaGIIndirectSpecular(LayaGIInput giInput,mediump float occlusion, vec4 glossIn)\r\n{\r\n\tmediump vec3 specular = layaGlossyEnvironment(glossIn);\r\n\treturn specular * occlusion;\r\n}\r\n\r\n\r\nLayaGI layaGlobalIllumination(LayaGIInput giInput,mediump float occlusion, mediump vec3 normalWorld,mediump vec4 uvwRoughness)\r\n{\r\n\tLayaGI gi;\r\n\tgi.diffuse = layaGIBase(giInput,occlusion, normalWorld);\r\n\tgi.specular = layaGIIndirectSpecular(giInput,occlusion, uvwRoughness);\r\n\treturn gi;\r\n}\r\n\r\n\r\n"; var LightingGLSL = "#ifdef GRAPHICS_API_GLES3\r\n\t#define INVERSE_MAT(mat) inverse(mat)\r\n#else\r\n\t#define INVERSE_MAT(mat) inverseMat(mat)\r\n#endif\r\n\r\nstruct DirectionLight {\r\n\tvec3 color;\r\n\tvec3 direction;\r\n};\r\n\r\nstruct PointLight {\r\n\tvec3 color;\r\n\tvec3 position;\r\n\tfloat range;\r\n};\r\n\r\nstruct SpotLight {\r\n\tvec3 color;\r\n\tvec3 position;\r\n\tfloat range;\r\n\tvec3 direction;\r\n\tfloat spot;\r\n};\r\n\r\nstruct LayaGI{\r\n\tvec3 diffuse;\r\n\tvec3 specular;\r\n};\r\n\r\nstruct LayaLight{\r\n\tvec3 color;\r\n\tvec3 dir;\r\n};\r\n\r\nconst int c_ClusterBufferWidth = CLUSTER_X_COUNT*CLUSTER_Y_COUNT;\r\nconst int c_ClusterBufferHeight = CLUSTER_Z_COUNT*(1+int(ceil(float(MAX_LIGHT_COUNT_PER_CLUSTER)/4.0)));\r\nconst int c_ClusterBufferFloatWidth = c_ClusterBufferWidth*4;\r\n\r\n#ifndef GRAPHICS_API_GLES3\r\n\tmat3 inverseMat(mat3 m) {\r\n\t\tfloat a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];\r\n\t\tfloat a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];\r\n\t\tfloat a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];\r\n\r\n\t\tfloat b01 = a22 * a11 - a12 * a21;\r\n\t\tfloat b11 = -a22 * a10 + a12 * a20;\r\n\t\tfloat b21 = a21 * a10 - a11 * a20;\r\n\r\n\t\tfloat det = a00 * b01 + a01 * b11 + a02 * b21;\r\n\r\n\t\treturn mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),\r\n\t\t\t\t\tb11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),\r\n\t\t\t\t\tb21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;\r\n\t}\r\n#endif\r\n\r\nivec4 getClusterInfo(sampler2D clusterBuffer,mat4 viewMatrix,vec4 viewport,vec3 position,vec4 fragCoord,vec4 projectParams)\r\n{\r\n\tvec3 viewPos = vec3(viewMatrix*vec4(position, 1.0)); //position in viewspace\r\n\r\n\tint clusterXIndex = int(floor(fragCoord.x/ (float(viewport.z)/float(CLUSTER_X_COUNT))));\r\n int clusterYIndex = int(floor((viewport.w * (projectParams.z <0.0? 0.0 : 1.0) - fragCoord.y * projectParams.z)/ (float(viewport.w)/float(CLUSTER_Y_COUNT))));//Maybe Flipped ProjectMatrix\r\n\tfloat zSliceParam =float(CLUSTER_Z_COUNT)/log2(projectParams.y / projectParams.x);\r\n \tint clusterZIndex = int(floor(log2(-viewPos.z) * zSliceParam- log2(projectParams.x) * zSliceParam));//projectParams x:cameraNear y:cameraFar\r\n\r\n\tvec2 uv= vec2((float(clusterXIndex + clusterYIndex * CLUSTER_X_COUNT)+0.5)/float(c_ClusterBufferWidth),\r\n\t\t\t\t(float(clusterZIndex)+0.5)/float(c_ClusterBufferHeight));\r\n\tvec4 clusterPixel=texture2D(clusterBuffer, uv);\r\n\treturn ivec4(clusterPixel);//X:Point Count Y:Spot Count Z、W:Light Offset\r\n}\r\n\r\n\r\nint getLightIndex(sampler2D clusterBuffer,int offset,int index) \r\n{\r\n\tint totalOffset=offset+index;\r\n\tint row=totalOffset/c_ClusterBufferFloatWidth;\r\n\tint lastRowFloat=totalOffset-row*c_ClusterBufferFloatWidth;\r\n\tint col=lastRowFloat/4;\r\n\tvec2 uv=vec2((float(col)+0.5)/float(c_ClusterBufferWidth),\r\n\t\t\t\t(float(row)+0.5)/float(c_ClusterBufferHeight));\r\n\tvec4 texel = texture2D(clusterBuffer, uv);\r\n int pixelComponent = lastRowFloat-col*4;\r\n if (pixelComponent == 0) \r\n return int(texel.x);\r\n else if (pixelComponent == 1) \r\n return int(texel.y);\r\n else if (pixelComponent == 2) \r\n return int(texel.z);\r\n else //pixelComponent==3\r\n return int(texel.w);\r\n}\r\n\r\nDirectionLight getDirectionLight(sampler2D lightBuffer,int index) \r\n{\r\n DirectionLight light;\r\n float v = (float(index)+0.5)/ float(MAX_LIGHT_COUNT);\r\n vec4 p1 = texture2D(lightBuffer, vec2(0.125,v));\r\n vec4 p2 = texture2D(lightBuffer, vec2(0.375,v));\r\n\tlight.color=p1.rgb;\r\n light.direction = p2.rgb;\r\n return light;\r\n}\r\n\r\nPointLight getPointLight(sampler2D lightBuffer,sampler2D clusterBuffer,ivec4 clusterInfo,int index) \r\n{\r\n PointLight light;\r\n\tint pointIndex=getLightIndex(clusterBuffer,clusterInfo.z*c_ClusterBufferFloatWidth+clusterInfo.w,index);\r\n float v = (float(pointIndex)+0.5)/ float(MAX_LIGHT_COUNT);\r\n vec4 p1 = texture2D(lightBuffer, vec2(0.125,v));\r\n vec4 p2 = texture2D(lightBuffer, vec2(0.375,v));\r\n\tlight.color=p1.rgb;\r\n\tlight.range = p1.a;\r\n light.position = p2.rgb;\r\n return light;\r\n}\r\n\r\nSpotLight getSpotLight(sampler2D lightBuffer,sampler2D clusterBuffer,ivec4 clusterInfo,int index) \r\n{\r\n SpotLight light;\r\n\tint spoIndex=getLightIndex(clusterBuffer,clusterInfo.z*c_ClusterBufferFloatWidth+clusterInfo.w,clusterInfo.x+index);\r\n float v = (float(spoIndex)+0.5)/ float(MAX_LIGHT_COUNT);\r\n vec4 p1 = texture2D(lightBuffer, vec2(0.125,v));\r\n vec4 p2 = texture2D(lightBuffer, vec2(0.375,v));\r\n\tvec4 p3 = texture2D(lightBuffer, vec2(0.625,v));\r\n light.color = p1.rgb;\r\n\tlight.range=p1.a;\r\n light.position = p2.rgb;\r\n\tlight.spot = p2.a;\r\n\tlight.direction = p3.rgb;\r\n return light;\r\n}\r\n\r\n// Laya中使用衰减纹理\r\nfloat LayaAttenuation(in vec3 L,in float invLightRadius) {\r\n\tfloat fRatio = clamp(length(L) * invLightRadius,0.0,1.0);\r\n\tfRatio *= fRatio;\r\n\treturn 1.0 / (1.0 + 25.0 * fRatio)* clamp(4.0*(1.0 - fRatio),0.0,1.0); //fade to black as if 4 pixel texture\r\n}\r\n\r\n// Same as Just Cause 2 and Crysis 2 (you can read GPU Pro 1 book for more information)\r\nfloat BasicAttenuation(in vec3 L,in float invLightRadius) {\r\n\tvec3 distance = L * invLightRadius;\r\n\tfloat attenuation = clamp(1.0 - dot(distance, distance),0.0,1.0); // Equals float attenuation = saturate(1.0f - dot(L, L) / (lightRadius * lightRadius));\r\n\treturn attenuation * attenuation;\r\n}\r\n\r\n// Inspired on http://fools.slindev.com/viewtopic.php?f=11&t=21&view=unread#unread\r\nfloat NaturalAttenuation(in vec3 L,in float invLightRadius) {\r\n\tfloat attenuationFactor = 30.0;\r\n\tvec3 distance = L * invLightRadius;\r\n\tfloat attenuation = dot(distance, distance); // Equals float attenuation = dot(L, L) / (lightRadius * lightRadius);\r\n\tattenuation = 1.0 / (attenuation * attenuationFactor + 1.0);\r\n\t// Second we move down the function therewith it reaches zero at abscissa 1:\r\n\tattenuationFactor = 1.0 / (attenuationFactor + 1.0); //attenuationFactor contains now the value we have to subtract\r\n\tattenuation = max(attenuation - attenuationFactor, 0.0); // The max fixes a bug.\r\n\t// Finally we expand the equation along the y-axis so that it starts with a function value of 1 again.\r\n\tattenuation /= 1.0 - attenuationFactor;\r\n\treturn attenuation;\r\n}\r\n\r\nvoid LayaAirBlinnPhongLight (in vec3 specColor,in float specColorIntensity,in vec3 normal,in vec3 gloss, in vec3 viewDir,in vec3 lightColor, in vec3 lightVec,out vec3 diffuseColor,out vec3 specularColor) {\r\n\tmediump vec3 h = normalize(viewDir-lightVec);\r\n\tlowp float ln = max (0.0, dot (-lightVec,normal));\r\n\tfloat nh = max (0.0, dot (h,normal));\r\n\tdiffuseColor=lightColor * ln;\r\n\tspecularColor=lightColor *specColor*pow (nh, specColorIntensity*128.0) * gloss;\r\n}\r\n\r\nvoid LayaAirBlinnPhongDiectionLight (in vec3 specColor,in float specColorIntensity,in vec3 normal,in vec3 gloss, in vec3 viewDir, in DirectionLight light,out vec3 diffuseColor,out vec3 specularColor) {\r\n\tvec3 lightVec=normalize(light.direction);\r\n\tLayaAirBlinnPhongLight(specColor,specColorIntensity,normal,gloss,viewDir,light.color,lightVec,diffuseColor,specularColor);\r\n}\r\n\r\nvoid LayaAirBlinnPhongPointLight (in vec3 pos,in vec3 specColor,in float specColorIntensity,in vec3 normal,in vec3 gloss, in vec3 viewDir, in PointLight light,out vec3 diffuseColor,out vec3 specularColor) {\r\n\tvec3 lightVec = pos-light.position;\r\n\tLayaAirBlinnPhongLight(specColor,specColorIntensity,normal,gloss,viewDir,light.color,lightVec/length(lightVec),diffuseColor,specularColor);\r\n\tfloat attenuate = LayaAttenuation(lightVec, 1.0/light.range);\r\n\tdiffuseColor *= attenuate;\r\n\tspecularColor*= attenuate;\r\n}\r\n\r\nvoid LayaAirBlinnPhongSpotLight (in vec3 pos,in vec3 specColor,in float specColorIntensity,in vec3 normal,in vec3 gloss, in vec3 viewDir, in SpotLight light,out vec3 diffuseColor,out vec3 specularColor) {\r\n\tvec3 lightVec = pos-light.position;\r\n\tvec3 normalLightVec=lightVec/length(lightVec);\r\n\tLayaAirBlinnPhongLight(specColor,specColorIntensity,normal,gloss,viewDir,light.color,normalLightVec,diffuseColor,specularColor);\r\n\tvec2 cosAngles=cos(vec2(light.spot,light.spot*0.5)*0.5);//ConeAttenuation\r\n\tfloat dl=dot(normalize(light.direction),normalLightVec);\r\n\tdl*=smoothstep(cosAngles[0],cosAngles[1],dl);\r\n\tfloat attenuate = LayaAttenuation(lightVec, 1.0/light.range)*dl;\r\n\tdiffuseColor *=attenuate;\r\n\tspecularColor *=attenuate;\r\n}\r\n\r\nvec3 NormalSampleToWorldSpace(vec3 normalMapSample, vec3 unitNormal, vec3 tangent,vec3 binormal) {\r\n\tvec3 normalT =vec3(2.0*normalMapSample.x - 1.0,1.0-2.0*normalMapSample.y,2.0*normalMapSample.z - 1.0);\r\n\tmediump vec3 N = unitNormal;\r\n\tmediump vec3 T = tangent;\r\n\tmediump vec3 B = binormal;\r\n\tmat3 TBN = mat3(T, B, N);\r\n\r\n\t// Transform from tangent space to world space.\r\n\tvec3 bumpedNormal =normalize(TBN*normalT);\r\n\treturn bumpedNormal;\r\n}\r\n\r\nvec3 NormalSampleToWorldSpace1(vec4 normalMapSample, vec3 tangent, vec3 binormal, vec3 unitNormal) {\r\n\tvec3 normalT;\r\n\tnormalT.x = 2.0 * normalMapSample.x - 1.0;\r\n\tnormalT.y = 1.0 - 2.0 * normalMapSample.y;\r\n\tnormalT.z = sqrt(1.0 - clamp(dot(normalT.xy, normalT.xy), 0.0, 1.0));\r\n\r\n\tvec3 T = normalize(tangent);\r\n\tvec3 B = normalize(binormal);\r\n\tvec3 N = normalize(unitNormal);\r\n\tmat3 TBN = mat3(T, B, N);\r\n\r\n\t// Transform from tangent space to world space.\r\n\tvec3 bumpedNormal = TBN * normalize(normalT);\r\n\r\n\treturn bumpedNormal;\r\n}\r\n\r\nvec3 DecodeLightmap(vec4 color) {\r\n\treturn color.rgb*color.a*5.0;\r\n}\r\n\r\nvec3 decodeHDR(vec4 color,float range) {\r\n\treturn color.rgb*color.a*range;\r\n}\r\n\r\nvec2 TransformUV(vec2 texcoord,vec4 tilingOffset) {\r\n\tvec2 transTexcoord=vec2(texcoord.x,texcoord.y-1.0)*tilingOffset.xy+vec2(tilingOffset.z,-tilingOffset.w);\r\n\ttransTexcoord.y+=1.0;\r\n\treturn transTexcoord;\r\n}\r\n\r\nvec4 remapGLPositionZ(vec4 position) {\r\n\tposition.z=position.z * 2.0 - position.w;\r\n\treturn position;\r\n}\r\n\r\nmediump vec3 layaLinearToGammaSpace (mediump vec3 linRGB)\r\n{\r\n linRGB = max(linRGB, vec3(0.0));\r\n // An almost-perfect approximation from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1\r\n return max(1.055 * pow(linRGB,vec3(0.416666667)) - 0.055, 0.0); \r\n}\r\n\r\nLayaLight layaDirectionLightToLight(in DirectionLight light,in float attenuate)\r\n{\r\n\tLayaLight relight;\r\n\trelight.color = light.color*attenuate;\r\n\trelight.dir = light.direction;\r\n\treturn relight;\r\n}\r\n\r\nLayaLight layaPointLightToLight(in vec3 pos,in vec3 normal, in PointLight light,in float attenuate)\r\n{\r\n\tLayaLight relight;\r\n\tvec3 lightVec = pos-light.position;\r\n\tattenuate *= LayaAttenuation(lightVec, 1.0/light.range);\r\n\trelight.color = light.color*attenuate;\r\n\trelight.dir = normalize(lightVec);\r\n\treturn relight;\r\n}\r\n\r\nLayaLight layaSpotLightToLight(in vec3 pos,in vec3 normal, in SpotLight light,in float attenuate)\r\n{\r\n\tLayaLight relight;\r\n\tvec3 lightVec = pos-light.position;\r\n\tvec3 normalLightVec=lightVec/length(lightVec);\r\n\tvec2 cosAngles=cos(vec2(light.spot,light.spot*0.5)*0.5);//ConeAttenuation\r\n\tfloat dl=dot(normalize(light.direction),normalLightVec);\r\n\tdl*=smoothstep(cosAngles[0],cosAngles[1],dl);\r\n\tattenuate *= LayaAttenuation(lightVec, 1.0/light.range)*dl;\r\n\trelight.dir = lightVec;\r\n\trelight.color = light.color*attenuate;\r\n\treturn relight;\r\n}\r\n\r\n"; var ShadowSampleTentGLSL = "// ------------------------------------------------------------------\r\n// PCF Filtering Tent Functions\r\n// ------------------------------------------------------------------\r\n\r\n// Assuming a isoceles right angled triangle of height \"triangleHeight\" (as drawn below).\r\n// This function return the area of the triangle above the first texel(in Y the first texel).\r\n//\r\n// |\\ <-- 45 degree slop isosceles right angled triangle\r\n// | \\\r\n// ---- <-- length of this side is \"triangleHeight\"\r\n// _ _ _ _ <-- texels\r\nfloat sampleShadowGetIRTriangleTexelArea(float triangleHeight)\r\n{\r\n return triangleHeight - 0.5;\r\n}\r\n\r\n// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.\r\n// This function return the area of the triangle above each of those texels.\r\n// | <-- offset from -0.5 to 0.5, 0 meaning triangle is exactly in the center\r\n// / \\ <-- 45 degree slop isosceles triangle (ie tent projected in 2D)\r\n// / \\\r\n// _ _ _ _ <-- texels\r\n// X Y Z W <-- result indices (in computedArea.xyzw and computedAreaUncut.xyzw)\r\n// Top point at (right,top) in a texel,left bottom point at (middle,middle) in a texel,right bottom point at (middle,middle) in a texel.\r\nvoid sampleShadowGetTexelAreasTent3x3(float offset, out vec4 computedArea, out vec4 computedAreaUncut)\r\n{\r\n // Compute the exterior areas,a and h is same.\r\n float a = offset + 0.5;\r\n float offsetSquaredHalved = a * a * 0.5;\r\n computedAreaUncut.x = computedArea.x = offsetSquaredHalved - offset;\r\n computedAreaUncut.w = computedArea.w = offsetSquaredHalved;\r\n\r\n // Compute the middle areas\r\n // For Y : We find the area in Y of as if the left section of the isoceles triangle would\r\n // intersect the axis between Y and Z (ie where offset = 0).\r\n computedAreaUncut.y = sampleShadowGetIRTriangleTexelArea(1.5 - offset);\r\n // This area is superior to the one we are looking for if (offset < 0) thus we need to\r\n // subtract the area of the triangle defined by (0,1.5-offset), (0,1.5+offset), (-offset,1.5).\r\n float clampedOffsetLeft = min(offset,0.0);\r\n float areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft;\r\n computedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle;\r\n\r\n // We do the same for the Z but with the right part of the isoceles triangle\r\n computedAreaUncut.z = sampleShadowGetIRTriangleTexelArea(1.5 + offset);\r\n float clampedOffsetRight = max(offset,0.0);\r\n float areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight;\r\n computedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle;\r\n}\r\n\r\n// Assuming a isoceles triangle of 2.5 texel height and 5 texels wide lying on 6 texels.\r\n// This function return the weight of each texels area relative to the full triangle area.\r\n// / \\\r\n// _ _ _ _ _ _ <-- texels\r\n// 0 1 2 3 4 5 <-- computed area indices (in texelsWeights[])\r\n// Top point at (right,top) in a texel,left bottom point at (middle,middle) in a texel,right bottom point at (middle,middle) in a texel.\r\nvoid sampleShadowGetTexelWeightsTent5x5(float offset, out vec3 texelsWeightsA, out vec3 texelsWeightsB)\r\n{\r\n vec4 areaFrom3texelTriangle;\r\n vec4 areaUncutFrom3texelTriangle;\r\n sampleShadowGetTexelAreasTent3x3(offset, areaFrom3texelTriangle, areaUncutFrom3texelTriangle);\r\n\r\n // Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.\r\n // the 5 texel wide triangle can be seen as the 3 texel wide one but shifted up by one unit/texel.\r\n // 0.16 is 1/(the triangle area)\r\n texelsWeightsA.x = 0.16 * (areaFrom3texelTriangle.x);\r\n texelsWeightsA.y = 0.16 * (areaUncutFrom3texelTriangle.y);\r\n texelsWeightsA.z = 0.16 * (areaFrom3texelTriangle.y + 1.0);\r\n texelsWeightsB.x = 0.16 * (areaFrom3texelTriangle.z + 1.0);\r\n texelsWeightsB.y = 0.16 * (areaUncutFrom3texelTriangle.z);\r\n texelsWeightsB.z = 0.16 * (areaFrom3texelTriangle.w);\r\n}\r\n\r\n// 5x5 Tent filter (45 degree sloped triangles in U and V)\r\nvoid sampleShadowComputeSamplesTent5x5(vec4 shadowMapTextureTexelSize, vec2 coord, out float fetchesWeights[9], out vec2 fetchesUV[9])\r\n{\r\n // tent base is 5x5 base thus covering from 25 to 36 texels, thus we need 9 bilinear PCF fetches\r\n vec2 tentCenterInTexelSpace = coord.xy * shadowMapTextureTexelSize.zw;\r\n vec2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);\r\n vec2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;\r\n\r\n // find the weight of each texel based on the area of a 45 degree slop tent above each of them.\r\n vec3 texelsWeightsUA, texelsWeightsUB;\r\n vec3 texelsWeightsVA, texelsWeightsVB;\r\n sampleShadowGetTexelWeightsTent5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsUA, texelsWeightsUB);\r\n sampleShadowGetTexelWeightsTent5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsVA, texelsWeightsVB);\r\n\r\n // each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels\r\n vec3 fetchesWeightsU = vec3(texelsWeightsUA.xz, texelsWeightsUB.y) + vec3(texelsWeightsUA.y, texelsWeightsUB.xz);\r\n vec3 fetchesWeightsV = vec3(texelsWeightsVA.xz, texelsWeightsVB.y) + vec3(texelsWeightsVA.y, texelsWeightsVB.xz);\r\n\r\n // move the PCF bilinear fetches to respect texels weights\r\n vec3 fetchesOffsetsU = vec3(texelsWeightsUA.y, texelsWeightsUB.xz) / fetchesWeightsU.xyz + vec3(-2.5,-0.5,1.5);\r\n vec3 fetchesOffsetsV = vec3(texelsWeightsVA.y, texelsWeightsVB.xz) / fetchesWeightsV.xyz + vec3(-2.5,-0.5,1.5);\r\n fetchesOffsetsU *= shadowMapTextureTexelSize.xxx;\r\n fetchesOffsetsV *= shadowMapTextureTexelSize.yyy;\r\n\r\n vec2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTextureTexelSize.xy;\r\n fetchesUV[0] = bilinearFetchOrigin + vec2(fetchesOffsetsU.x, fetchesOffsetsV.x);\r\n fetchesUV[1] = bilinearFetchOrigin + vec2(fetchesOffsetsU.y, fetchesOffsetsV.x);\r\n fetchesUV[2] = bilinearFetchOrigin + vec2(fetchesOffsetsU.z, fetchesOffsetsV.x);\r\n fetchesUV[3] = bilinearFetchOrigin + vec2(fetchesOffsetsU.x, fetchesOffsetsV.y);\r\n fetchesUV[4] = bilinearFetchOrigin + vec2(fetchesOffsetsU.y, fetchesOffsetsV.y);\r\n fetchesUV[5] = bilinearFetchOrigin + vec2(fetchesOffsetsU.z, fetchesOffsetsV.y);\r\n fetchesUV[6] = bilinearFetchOrigin + vec2(fetchesOffsetsU.x, fetchesOffsetsV.z);\r\n fetchesUV[7] = bilinearFetchOrigin + vec2(fetchesOffsetsU.y, fetchesOffsetsV.z);\r\n fetchesUV[8] = bilinearFetchOrigin + vec2(fetchesOffsetsU.z, fetchesOffsetsV.z);\r\n\r\n fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;\r\n fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;\r\n fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;\r\n fetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y;\r\n fetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y;\r\n fetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y;\r\n fetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z;\r\n fetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z;\r\n fetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z;\r\n}"; var linePS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\nprecision highp float;\r\n#else\r\nprecision mediump float;\r\n#endif\r\n\r\nvarying vec4 v_Color;\r\nuniform vec4 u_Color;\r\n\r\nvoid main()\r\n{\r\n gl_FragColor = v_Color * u_Color; \r\n}\r\n\r\n"; var lineVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_Position;\r\nuniform mat4 u_MvpMatrix;\r\nuniform vec4 u_Color;\r\nattribute vec4 a_Color;\r\nvarying vec4 v_Color;\r\n\r\n\r\nvoid main()\r\n{\r\n\tgl_Position = u_MvpMatrix * a_Position;\r\n\tv_Color=a_Color*u_Color;\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}"; var MeshBlinnPhongPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n\tprecision highp int;\r\n#else\r\n\tprecision mediump float;\r\n\tprecision mediump int;\r\n#endif\r\n\r\n#include \"Lighting.glsl\";\r\n#include \"Shadow.glsl\"\r\n\r\nuniform vec4 u_DiffuseColor;\r\n\r\n#if defined(COLOR)&&defined(ENABLEVERTEXCOLOR)\r\n\tvarying vec4 v_Color;\r\n#endif\r\n\r\n#ifdef ALPHATEST\r\n\tuniform float u_AlphaTestValue;\r\n#endif\r\n\r\n#ifdef DIFFUSEMAP\r\n\tuniform sampler2D u_DiffuseTexture;\r\n#endif\r\n\r\n\r\n#if defined(DIFFUSEMAP)||((defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT))&&(defined(SPECULARMAP)||defined(NORMALMAP)))\r\n\tvarying vec2 v_Texcoord0;\r\n#endif\r\n\r\n#ifdef LIGHTMAP\r\n\tvarying vec2 v_LightMapUV;\r\n\tuniform sampler2D u_LightMap;\r\n#endif\r\n\r\nvarying vec3 v_Normal;\r\n#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\tvarying vec3 v_ViewDir; \r\n\r\n\tuniform vec3 u_MaterialSpecular;\r\n\tuniform float u_Shininess;\r\n\r\n\t#ifdef LEGACYSINGLELIGHTING\r\n\t\t#ifdef DIRECTIONLIGHT\r\n\t\t\tuniform DirectionLight u_DirectionLight;\r\n\t\t#endif\r\n\t\t#ifdef POINTLIGHT\r\n\t\t\tuniform PointLight u_PointLight;\r\n\t\t#endif\r\n\t\t#ifdef SPOTLIGHT\r\n\t\t\tuniform SpotLight u_SpotLight;\r\n\t\t#endif\r\n\t#else\r\n\t\tuniform mat4 u_View;\r\n\t\tuniform vec4 u_ProjectionParams;\r\n\t\tuniform vec4 u_Viewport;\r\n\t\tuniform int u_DirationLightCount;\r\n\t\tuniform sampler2D u_LightBuffer;\r\n\t\tuniform sampler2D u_LightClusterBuffer;\r\n\t#endif\r\n\r\n\t#ifdef SPECULARMAP \r\n\t\tuniform sampler2D u_SpecularTexture;\r\n\t#endif\r\n#endif\r\n\r\n#ifdef NORMALMAP \r\n\tuniform sampler2D u_NormalTexture;\r\n\tvarying vec3 v_Tangent;\r\n\tvarying vec3 v_Binormal;\r\n#endif\r\n\r\n#ifdef FOG\r\n\tuniform float u_FogStart;\r\n\tuniform float u_FogRange;\r\n\tuniform vec3 u_FogColor;\r\n#endif\r\n\r\n#if defined(POINTLIGHT)||defined(SPOTLIGHT)||(defined(CALCULATE_SHADOWS)&&defined(SHADOW_CASCADE))||defined(CALCULATE_SPOTSHADOWS)\r\n\tvarying vec3 v_PositionWorld;\r\n#endif\r\n\r\n\r\n#include \"GlobalIllumination.glsl\";//\"GlobalIllumination.glsl use uniform should at front of this\r\n\r\n#if defined(CALCULATE_SHADOWS)&&!defined(SHADOW_CASCADE)\r\n\tvarying vec4 v_ShadowCoord;\r\n#endif\r\n\r\n#ifdef CALCULATE_SPOTSHADOWS\r\n\tvarying vec4 v_SpotShadowCoord;\r\n#endif\r\n\r\n\r\nvoid main()\r\n{\r\n\tvec3 normal;//light and SH maybe use normal\r\n\t#if defined(NORMALMAP)\r\n\t\tvec3 normalMapSample = texture2D(u_NormalTexture, v_Texcoord0).rgb;\r\n\t\tnormal = normalize(NormalSampleToWorldSpace(normalMapSample, v_Normal, v_Tangent,v_Binormal));\r\n\t#else\r\n\t\tnormal = normalize(v_Normal);\r\n\t#endif\r\n\r\n\t#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t\tvec3 viewDir= normalize(v_ViewDir);\r\n\t#endif\r\n\r\n\tLayaGIInput giInput;\r\n\t#ifdef LIGHTMAP\t\r\n\t\tgiInput.lightmapUV=v_LightMapUV;\r\n\t#endif\r\n\tvec3 globalDiffuse=layaGIBase(giInput,1.0,normal);\r\n\t\r\n\tvec4 mainColor=u_DiffuseColor;\r\n\t#ifdef DIFFUSEMAP\r\n\t\tvec4 difTexColor=texture2D(u_DiffuseTexture, v_Texcoord0);\r\n\t\tmainColor=mainColor*difTexColor;\r\n\t#endif \r\n\t#if defined(COLOR)&&defined(ENABLEVERTEXCOLOR)\r\n\t\tmainColor=mainColor*v_Color;\r\n\t#endif \r\n \r\n\t#ifdef ALPHATEST\r\n\t\tif(mainColor.a= u_DirationLightCount)\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tDirectionLight directionLight = getDirectionLight(u_LightBuffer,i);\r\n\t\t\t\t#ifdef CALCULATE_SHADOWS\r\n\t\t\t\t\tif(i == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t#ifdef SHADOW_CASCADE\r\n\t\t\t\t\t\t\tvec4 shadowCoord = getShadowCoord(vec4(v_PositionWorld,1.0));\r\n\t\t\t\t\t\t#else\r\n\t\t\t\t\t\t\tvec4 shadowCoord = v_ShadowCoord;\r\n\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\tdirectionLight.color *= sampleShadowmap(shadowCoord);\r\n\t\t\t\t\t}\r\n\t\t\t\t#endif\r\n\t\t\t\tLayaAirBlinnPhongDiectionLight(u_MaterialSpecular,u_Shininess,normal,gloss,viewDir,directionLight,dif,spe);\r\n\t\t\t\tdiffuse+=dif;\r\n\t\t\t\tspecular+=spe;\r\n\t\t\t}\r\n\t\t#endif\r\n\t\t#if defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t\t\tivec4 clusterInfo =getClusterInfo(u_LightClusterBuffer,u_View,u_Viewport, v_PositionWorld,gl_FragCoord,u_ProjectionParams);\r\n\t\t\t#ifdef POINTLIGHT\r\n\t\t\t\tfor (int i = 0; i < MAX_LIGHT_COUNT; i++) \r\n\t\t\t\t{\r\n\t\t\t\t\tif(i >= clusterInfo.x)//PointLightCount\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tPointLight pointLight = getPointLight(u_LightBuffer,u_LightClusterBuffer,clusterInfo,i);\r\n\t\t\t\t\tLayaAirBlinnPhongPointLight(v_PositionWorld,u_MaterialSpecular,u_Shininess,normal,gloss,viewDir,pointLight,dif,spe);\r\n\t\t\t\t\tdiffuse+=dif;\r\n\t\t\t\t\tspecular+=spe;\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t\t#ifdef SPOTLIGHT\r\n\t\t\t\tfor (int i = 0; i < MAX_LIGHT_COUNT; i++) \r\n\t\t\t\t{\r\n\t\t\t\t\tif(i >= clusterInfo.y)//SpotLightCount\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tSpotLight spotLight = getSpotLight(u_LightBuffer,u_LightClusterBuffer,clusterInfo,i);\r\n\t\t\t\t\t#ifdef CALCULATE_SPOTSHADOWS\r\n\t\t\t\t\t\tif(i == 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tvec4 spotShadowcoord = v_SpotShadowCoord;\r\n\t\t\t\t\t\t\tspotLight.color *= sampleSpotShadowmap(spotShadowcoord);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t#endif\r\n\t\t\t\t\tLayaAirBlinnPhongSpotLight(v_PositionWorld,u_MaterialSpecular,u_Shininess,normal,gloss,viewDir,spotLight,dif,spe);\r\n\t\t\t\t\tdiffuse+=dif;\r\n\t\t\t\t\tspecular+=spe;\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t#endif\r\n\t#endif\r\n\r\n\tgl_FragColor =vec4(mainColor.rgb*(globalDiffuse + diffuse),mainColor.a);\r\n\r\n\t#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t\tgl_FragColor.rgb+=specular;\r\n\t#endif\r\n\t \r\n\t#ifdef FOG\r\n\t\tfloat lerpFact=clamp((1.0/gl_FragCoord.w-u_FogStart)/u_FogRange,0.0,1.0);\r\n\t\tgl_FragColor.rgb=mix(gl_FragColor.rgb,u_FogColor,lerpFact);\r\n\t#endif\r\n}\r\n\r\n"; var MeshBlinnPhongVS = "#include \"Lighting.glsl\";\r\n#include \"Shadow.glsl\";\r\n\r\nattribute vec4 a_Position;\r\n\r\n#ifdef GPU_INSTANCE\r\n\tattribute mat4 a_MvpMatrix;\r\n#else\r\n\tuniform mat4 u_MvpMatrix;\r\n#endif\r\n\r\n#if defined(DIFFUSEMAP)||((defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT))&&(defined(SPECULARMAP)||defined(NORMALMAP)))||(defined(LIGHTMAP)&&defined(UV))\r\n\tattribute vec2 a_Texcoord0;\r\n\tvarying vec2 v_Texcoord0;\r\n#endif\r\n\r\n#if defined(LIGHTMAP)&&defined(UV1)\r\n\tattribute vec2 a_Texcoord1;\r\n#endif\r\n\r\n#ifdef LIGHTMAP\r\n\tuniform vec4 u_LightmapScaleOffset;\r\n\tvarying vec2 v_LightMapUV;\r\n#endif\r\n\r\n#ifdef COLOR\r\n\tattribute vec4 a_Color;\r\n\tvarying vec4 v_Color;\r\n#endif\r\n\r\n#ifdef BONE\r\n\tconst int c_MaxBoneCount = 24;\r\n\tattribute vec4 a_BoneIndices;\r\n\tattribute vec4 a_BoneWeights;\r\n\tuniform mat4 u_Bones[c_MaxBoneCount];\r\n#endif\r\n\r\nattribute vec3 a_Normal;\r\nvarying vec3 v_Normal; \r\n\r\n#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\tuniform vec3 u_CameraPos;\r\n\tvarying vec3 v_ViewDir; \r\n#endif\r\n\r\n#if defined(NORMALMAP)\r\n\tattribute vec4 a_Tangent0;\r\n\tvarying vec3 v_Tangent;\r\n\tvarying vec3 v_Binormal;\r\n#endif\r\n\r\n#ifdef GPU_INSTANCE\r\n\tattribute mat4 a_WorldMat;\r\n#else\r\n\tuniform mat4 u_WorldMat;\r\n#endif\r\n\r\n#if defined(POINTLIGHT)||defined(SPOTLIGHT)||(defined(CALCULATE_SHADOWS)&&defined(SHADOW_CASCADE))||defined(CALCULATE_SPOTSHADOWS)\r\n\tvarying vec3 v_PositionWorld;\r\n#endif\r\n\r\n#if defined(CALCULATE_SHADOWS)&&!defined(SHADOW_CASCADE)\r\n\tvarying vec4 v_ShadowCoord;\r\n#endif\r\n\r\n#ifdef CALCULATE_SPOTSHADOWS\r\n\tvarying vec4 v_SpotShadowCoord;\r\n#endif\r\n\r\n#ifdef TILINGOFFSET\r\n\tuniform vec4 u_TilingOffset;\r\n#endif\r\n\r\nvoid main()\r\n{\r\n\tvec4 position;\r\n\t#ifdef BONE\r\n\t\tmat4 skinTransform = u_Bones[int(a_BoneIndices.x)] * a_BoneWeights.x;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.y)] * a_BoneWeights.y;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.z)] * a_BoneWeights.z;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.w)] * a_BoneWeights.w;\r\n\t\tposition=skinTransform*a_Position;\r\n\t#else\r\n\t\tposition=a_Position;\r\n\t#endif\r\n\t#ifdef GPU_INSTANCE\r\n\t\tgl_Position = a_MvpMatrix * position;\r\n\t#else\r\n\t\tgl_Position = u_MvpMatrix * position;\r\n\t#endif\r\n\t\r\n\tmat4 worldMat;\r\n\t#ifdef GPU_INSTANCE\r\n\t\tworldMat = a_WorldMat;\r\n\t#else\r\n\t\tworldMat = u_WorldMat;\r\n\t#endif\r\n\r\n\tmat3 worldInvMat;\r\n\t#ifdef BONE\r\n\t\tworldInvMat=INVERSE_MAT(mat3(worldMat*skinTransform));\r\n\t#else\r\n\t\tworldInvMat=INVERSE_MAT(mat3(worldMat));\r\n\t#endif \r\n\tv_Normal=normalize(a_Normal*worldInvMat);\r\n\t#if defined(NORMALMAP)\r\n\t\tv_Tangent=normalize(a_Tangent0.xyz*worldInvMat);\r\n\t\tv_Binormal=cross(v_Normal,v_Tangent)*a_Tangent0.w;\r\n\t#endif\r\n\r\n\t#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)||(defined(CALCULATE_SHADOWS)&&defined(SHADOW_CASCADE))||defined(CALCULATE_SPOTSHADOWS)\r\n\t\tvec3 positionWS=(worldMat*position).xyz;\r\n\t\t#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t\t\tv_ViewDir = u_CameraPos-positionWS;\r\n\t\t#endif\r\n\t\t#if defined(POINTLIGHT)||defined(SPOTLIGHT)||(defined(CALCULATE_SHADOWS)&&defined(SHADOW_CASCADE))||defined(CALCULATE_SPOTSHADOWS)\r\n\t\t\tv_PositionWorld = positionWS;\r\n\t\t#endif\r\n\t#endif\r\n\r\n\t#if defined(DIFFUSEMAP)||((defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT))&&(defined(SPECULARMAP)||defined(NORMALMAP)))\r\n\t\t#ifdef TILINGOFFSET\r\n\t\t\tv_Texcoord0=TransformUV(a_Texcoord0,u_TilingOffset);\r\n\t\t#else\r\n\t\t\tv_Texcoord0=a_Texcoord0;\r\n\t\t#endif\r\n\t#endif\r\n\r\n\t#ifdef LIGHTMAP\r\n\t\t#ifdef UV1\r\n\t\t\tv_LightMapUV=vec2(a_Texcoord1.x,1.0-a_Texcoord1.y)*u_LightmapScaleOffset.xy+u_LightmapScaleOffset.zw;\r\n\t\t#else\r\n\t\t\tv_LightMapUV=vec2(a_Texcoord0.x,1.0-a_Texcoord0.y)*u_LightmapScaleOffset.xy+u_LightmapScaleOffset.zw;\r\n\t\t#endif \r\n\t\tv_LightMapUV.y=1.0-v_LightMapUV.y;\r\n\t#endif\r\n\r\n\t#if defined(COLOR)&&defined(ENABLEVERTEXCOLOR)\r\n\t\tv_Color=a_Color;\r\n\t#endif\r\n\r\n\t#if defined(CALCULATE_SHADOWS)&&!defined(SHADOW_CASCADE)\r\n\t\tv_ShadowCoord =getShadowCoord(vec4(positionWS,1.0));\r\n\t#endif\r\n\r\n\t#ifdef CALCULATE_SPOTSHADOWS\r\n\t\tv_SpotShadowCoord = u_SpotViewProjectMatrix*vec4(positionWS,1.0);\r\n\t#endif\r\n\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}"; var MeshBlinnPhongShadowCasterPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n\tprecision highp int;\r\n#else\r\n\tprecision mediump float;\r\n\tprecision mediump int;\r\n#endif\r\n\r\n#include \"ShadowCasterFS.glsl\"\r\n\r\nvoid main()\r\n{\r\n\tgl_FragColor=shadowCasterFragment();\r\n}"; var MeshBlinnPhongShadowCasterVS = "#include \"ShadowCasterVS.glsl\"\r\n\r\nvoid main()\r\n{\r\n\tvec4 positionCS = shadowCasterVertex();\r\n\tgl_Position=remapGLPositionZ(positionCS);\r\n}"; var ParticleShuriKenPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n precision highp float;\r\n#else\r\n precision mediump float;\r\n#endif\r\n\r\nvarying vec4 v_Color;\r\nvarying vec2 v_TextureCoordinate;\r\nuniform sampler2D u_texture;\r\nuniform vec4 u_Tintcolor;\r\n\r\n#ifdef RENDERMODE_MESH\r\n\tvarying vec4 v_MeshColor;\r\n#endif\r\n\r\n#ifdef FOG\r\n\tuniform float u_FogStart;\r\n\tuniform float u_FogRange;\r\n\t#ifdef ADDTIVEFOG\r\n\t#else\r\n\t\tuniform vec3 u_FogColor;\r\n\t#endif\r\n#endif\r\n\r\n\r\nvoid main()\r\n{\t\r\n\t#ifdef RENDERMODE_MESH\r\n\t\tgl_FragColor=v_MeshColor;\r\n\t#else\r\n\t\tgl_FragColor=vec4(1.0);\t\r\n\t#endif\r\n\t\t\r\n\t#ifdef DIFFUSEMAP\r\n\t\t#ifdef TINTCOLOR\r\n\t\t\tgl_FragColor*=texture2D(u_texture,v_TextureCoordinate)*u_Tintcolor*2.0*v_Color;\r\n\t\t#else\r\n\t\t\tgl_FragColor*=texture2D(u_texture,v_TextureCoordinate)*v_Color;\r\n\t\t#endif\r\n\t#else\r\n\t\t#ifdef TINTCOLOR\r\n\t\t\tgl_FragColor*=u_Tintcolor*2.0*v_Color;\r\n\t\t#else\r\n\t\t\tgl_FragColor*=v_Color;\r\n\t\t#endif\r\n\t#endif\r\n\t\r\n\t#ifdef FOG\r\n\t\tfloat lerpFact=clamp((1.0/gl_FragCoord.w-u_FogStart)/u_FogRange,0.0,1.0);\r\n\t\t#ifdef ADDTIVEFOG\r\n\t\t\tgl_FragColor.rgb=mix(gl_FragColor.rgb,vec3(0.0,0.0,0.0),lerpFact);\r\n\t\t#else\r\n\t\t\tgl_FragColor.rgb=mix(gl_FragColor.rgb,u_FogColor,lerpFact);\r\n\t\t#endif\r\n\t#endif\r\n}"; var ParticleShuriKenVS = "#include \"Lighting.glsl\";\r\n\r\n#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n precision highp float;\r\n#else\r\n precision mediump float;\r\n#endif\r\n\r\n#if defined(SPHERHBILLBOARD)||defined(STRETCHEDBILLBOARD)||defined(HORIZONTALBILLBOARD)||defined(VERTICALBILLBOARD)\r\n\tattribute vec4 a_CornerTextureCoordinate;\r\n#endif\r\n#ifdef RENDERMODE_MESH\r\n\tattribute vec3 a_MeshPosition;\r\n\tattribute vec4 a_MeshColor;\r\n\tattribute vec2 a_MeshTextureCoordinate;\r\n\tvarying vec4 v_MeshColor;\r\n#endif\r\n\r\nattribute vec4 a_ShapePositionStartLifeTime;\r\nattribute vec4 a_DirectionTime;\r\nattribute vec4 a_StartColor;\r\nattribute vec3 a_StartSize;\r\nattribute vec3 a_StartRotation0;\r\nattribute float a_StartSpeed;\r\n#if defined(COLOROVERLIFETIME)||defined(RANDOMCOLOROVERLIFETIME)||defined(SIZEOVERLIFETIMERANDOMCURVES)||defined(SIZEOVERLIFETIMERANDOMCURVESSEPERATE)||defined(ROTATIONOVERLIFETIMERANDOMCONSTANTS)||defined(ROTATIONOVERLIFETIMERANDOMCURVES)\r\n attribute vec4 a_Random0;\r\n#endif\r\n#if defined(TEXTURESHEETANIMATIONRANDOMCURVE)||defined(VELOCITYOVERLIFETIMERANDOMCONSTANT)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)\r\n attribute vec4 a_Random1;\r\n#endif\r\nattribute vec3 a_SimulationWorldPostion;\r\nattribute vec4 a_SimulationWorldRotation;\r\n\r\nvarying vec4 v_Color;\r\n#ifdef DIFFUSEMAP\r\n\tvarying vec2 v_TextureCoordinate;\r\n#endif\r\n\r\nuniform float u_CurrentTime;\r\nuniform vec3 u_Gravity;\r\n\r\nuniform vec3 u_WorldPosition;\r\nuniform vec4 u_WorldRotation;\r\nuniform bool u_ThreeDStartRotation;\r\nuniform int u_ScalingMode;\r\nuniform vec3 u_PositionScale;\r\nuniform vec3 u_SizeScale;\r\nuniform mat4 u_View;\r\nuniform mat4 u_Projection;\r\n\r\n#ifdef STRETCHEDBILLBOARD\r\n\tuniform vec3 u_CameraPos;\r\n#endif\r\nuniform vec3 u_CameraDirection;//TODO:只有几种广告牌模式需要用\r\nuniform vec3 u_CameraUp;\r\n\r\nuniform float u_StretchedBillboardLengthScale;\r\nuniform float u_StretchedBillboardSpeedScale;\r\nuniform int u_SimulationSpace;\r\n\r\n#if defined(VELOCITYOVERLIFETIMECONSTANT)||defined(VELOCITYOVERLIFETIMECURVE)||defined(VELOCITYOVERLIFETIMERANDOMCONSTANT)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)\r\n uniform int u_VOLSpaceType;\r\n#endif\r\n#if defined(VELOCITYOVERLIFETIMECONSTANT)||defined(VELOCITYOVERLIFETIMERANDOMCONSTANT)\r\n uniform vec3 u_VOLVelocityConst;\r\n#endif\r\n#if defined(VELOCITYOVERLIFETIMECURVE)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)\r\n uniform vec2 u_VOLVelocityGradientX[4];//x为key,y为速度\r\n uniform vec2 u_VOLVelocityGradientY[4];//x为key,y为速度\r\n uniform vec2 u_VOLVelocityGradientZ[4];//x为key,y为速度\r\n#endif\r\n#ifdef VELOCITYOVERLIFETIMERANDOMCONSTANT\r\n uniform vec3 u_VOLVelocityConstMax;\r\n#endif\r\n#ifdef VELOCITYOVERLIFETIMERANDOMCURVE\r\n uniform vec2 u_VOLVelocityGradientMaxX[4];//x为key,y为速度\r\n uniform vec2 u_VOLVelocityGradientMaxY[4];//x为key,y为速度\r\n uniform vec2 u_VOLVelocityGradientMaxZ[4];//x为key,y为速度\r\n#endif\r\n\r\n#ifdef COLOROVERLIFETIME\r\n uniform vec4 u_ColorOverLifeGradientColors[4];//x为key,yzw为Color\r\n uniform vec2 u_ColorOverLifeGradientAlphas[4];//x为key,y为Alpha\r\n#endif\r\n#ifdef RANDOMCOLOROVERLIFETIME\r\n uniform vec4 u_ColorOverLifeGradientColors[4];//x为key,yzw为Color\r\n uniform vec2 u_ColorOverLifeGradientAlphas[4];//x为key,y为Alpha\r\n uniform vec4 u_MaxColorOverLifeGradientColors[4];//x为key,yzw为Color\r\n uniform vec2 u_MaxColorOverLifeGradientAlphas[4];//x为key,y为Alpha\r\n#endif\r\n\r\n\r\n#if defined(SIZEOVERLIFETIMECURVE)||defined(SIZEOVERLIFETIMERANDOMCURVES)\r\n uniform vec2 u_SOLSizeGradient[4];//x为key,y为尺寸\r\n#endif\r\n#ifdef SIZEOVERLIFETIMERANDOMCURVES\r\n uniform vec2 u_SOLSizeGradientMax[4];//x为key,y为尺寸\r\n#endif\r\n#if defined(SIZEOVERLIFETIMECURVESEPERATE)||defined(SIZEOVERLIFETIMERANDOMCURVESSEPERATE)\r\n uniform vec2 u_SOLSizeGradientX[4];//x为key,y为尺寸\r\n uniform vec2 u_SOLSizeGradientY[4];//x为key,y为尺寸\r\n uniform vec2 u_SOLSizeGradientZ[4];//x为key,y为尺寸\r\n#endif\r\n#ifdef SIZEOVERLIFETIMERANDOMCURVESSEPERATE\r\n uniform vec2 u_SOLSizeGradientMaxX[4];//x为key,y为尺寸\r\n uniform vec2 u_SOLSizeGradientMaxY[4];//x为key,y为尺寸\r\n uniform vec2 u_SOLSizeGradientMaxZ[4];//x为key,y为尺寸\r\n#endif\r\n\r\n\r\n#ifdef ROTATIONOVERLIFETIME\r\n #if defined(ROTATIONOVERLIFETIMECONSTANT)||defined(ROTATIONOVERLIFETIMERANDOMCONSTANTS)\r\n uniform float u_ROLAngularVelocityConst;\r\n #endif\r\n #ifdef ROTATIONOVERLIFETIMERANDOMCONSTANTS\r\n uniform float u_ROLAngularVelocityConstMax;\r\n #endif\r\n #if defined(ROTATIONOVERLIFETIMECURVE)||defined(ROTATIONOVERLIFETIMERANDOMCURVES)\r\n uniform vec2 u_ROLAngularVelocityGradient[4];//x为key,y为旋转\r\n #endif\r\n #ifdef ROTATIONOVERLIFETIMERANDOMCURVES\r\n uniform vec2 u_ROLAngularVelocityGradientMax[4];//x为key,y为旋转\r\n #endif\r\n#endif\r\n#ifdef ROTATIONOVERLIFETIMESEPERATE\r\n #if defined(ROTATIONOVERLIFETIMECONSTANT)||defined(ROTATIONOVERLIFETIMERANDOMCONSTANTS)\r\n uniform vec3 u_ROLAngularVelocityConstSeprarate;\r\n #endif\r\n #ifdef ROTATIONOVERLIFETIMERANDOMCONSTANTS\r\n uniform vec3 u_ROLAngularVelocityConstMaxSeprarate;\r\n #endif\r\n #if defined(ROTATIONOVERLIFETIMECURVE)||defined(ROTATIONOVERLIFETIMERANDOMCURVES)\r\n uniform vec2 u_ROLAngularVelocityGradientX[4];\r\n uniform vec2 u_ROLAngularVelocityGradientY[4];\r\n uniform vec2 u_ROLAngularVelocityGradientZ[4];\r\n #endif\r\n #ifdef ROTATIONOVERLIFETIMERANDOMCURVES\r\n uniform vec2 u_ROLAngularVelocityGradientMaxX[4];\r\n uniform vec2 u_ROLAngularVelocityGradientMaxY[4];\r\n uniform vec2 u_ROLAngularVelocityGradientMaxZ[4];\r\n\tuniform vec2 u_ROLAngularVelocityGradientMaxW[4];\r\n #endif\r\n#endif\r\n\r\n#if defined(TEXTURESHEETANIMATIONCURVE)||defined(TEXTURESHEETANIMATIONRANDOMCURVE)\r\n uniform float u_TSACycles;\r\n uniform vec2 u_TSASubUVLength;\r\n uniform vec2 u_TSAGradientUVs[4];//x为key,y为frame\r\n#endif\r\n#ifdef TEXTURESHEETANIMATIONRANDOMCURVE\r\n uniform vec2 u_TSAMaxGradientUVs[4];//x为key,y为frame\r\n#endif\r\n\r\n#ifdef TILINGOFFSET\r\n\tuniform vec4 u_TilingOffset;\r\n#endif\r\n\r\nvec3 rotationByEuler(in vec3 vector,in vec3 rot)\r\n{\r\n\tfloat halfRoll = rot.z * 0.5;\r\n float halfPitch = rot.x * 0.5;\r\n\tfloat halfYaw = rot.y * 0.5;\r\n\r\n\tfloat sinRoll = sin(halfRoll);\r\n\tfloat cosRoll = cos(halfRoll);\r\n\tfloat sinPitch = sin(halfPitch);\r\n\tfloat cosPitch = cos(halfPitch);\r\n\tfloat sinYaw = sin(halfYaw);\r\n\tfloat cosYaw = cos(halfYaw);\r\n\r\n\tfloat quaX = (cosYaw * sinPitch * cosRoll) + (sinYaw * cosPitch * sinRoll);\r\n\tfloat quaY = (sinYaw * cosPitch * cosRoll) - (cosYaw * sinPitch * sinRoll);\r\n\tfloat quaZ = (cosYaw * cosPitch * sinRoll) - (sinYaw * sinPitch * cosRoll);\r\n\tfloat quaW = (cosYaw * cosPitch * cosRoll) + (sinYaw * sinPitch * sinRoll);\r\n\t\r\n\t//vec4 q=vec4(quaX,quaY,quaZ,quaW);\r\n\t//vec3 temp = cross(q.xyz, vector) + q.w * vector;\r\n\t//return (cross(temp, -q.xyz) + dot(q.xyz,vector) * q.xyz + q.w * temp);\r\n\t\r\n\tfloat x = quaX + quaX;\r\n float y = quaY + quaY;\r\n float z = quaZ + quaZ;\r\n float wx = quaW * x;\r\n float wy = quaW * y;\r\n float wz = quaW * z;\r\n\tfloat xx = quaX * x;\r\n float xy = quaX * y;\r\n\tfloat xz = quaX * z;\r\n float yy = quaY * y;\r\n float yz = quaY * z;\r\n float zz = quaZ * z;\r\n\r\n return vec3(((vector.x * ((1.0 - yy) - zz)) + (vector.y * (xy - wz))) + (vector.z * (xz + wy)),\r\n ((vector.x * (xy + wz)) + (vector.y * ((1.0 - xx) - zz))) + (vector.z * (yz - wx)),\r\n ((vector.x * (xz - wy)) + (vector.y * (yz + wx))) + (vector.z * ((1.0 - xx) - yy)));\r\n\t\r\n}\r\n\r\n//假定axis已经归一化\r\nvec3 rotationByAxis(in vec3 vector,in vec3 axis, in float angle)\r\n{\r\n\tfloat halfAngle = angle * 0.5;\r\n\tfloat sin = sin(halfAngle);\r\n\t\r\n\tfloat quaX = axis.x * sin;\r\n\tfloat quaY = axis.y * sin;\r\n\tfloat quaZ = axis.z * sin;\r\n\tfloat quaW = cos(halfAngle);\r\n\t\r\n\t//vec4 q=vec4(quaX,quaY,quaZ,quaW);\r\n\t//vec3 temp = cross(q.xyz, vector) + q.w * vector;\r\n\t//return (cross(temp, -q.xyz) + dot(q.xyz,vector) * q.xyz + q.w * temp);\r\n\t\r\n\tfloat x = quaX + quaX;\r\n float y = quaY + quaY;\r\n float z = quaZ + quaZ;\r\n float wx = quaW * x;\r\n float wy = quaW * y;\r\n float wz = quaW * z;\r\n\tfloat xx = quaX * x;\r\n float xy = quaX * y;\r\n\tfloat xz = quaX * z;\r\n float yy = quaY * y;\r\n float yz = quaY * z;\r\n float zz = quaZ * z;\r\n\r\n return vec3(((vector.x * ((1.0 - yy) - zz)) + (vector.y * (xy - wz))) + (vector.z * (xz + wy)),\r\n ((vector.x * (xy + wz)) + (vector.y * ((1.0 - xx) - zz))) + (vector.z * (yz - wx)),\r\n ((vector.x * (xz - wy)) + (vector.y * (yz + wx))) + (vector.z * ((1.0 - xx) - yy)));\r\n\t\r\n}\r\n\r\nvec3 rotationByQuaternions(in vec3 v,in vec4 q) \r\n{\r\n\treturn v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);\r\n}\r\n\r\n \r\n#if defined(VELOCITYOVERLIFETIMECURVE)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)||defined(SIZEOVERLIFETIMECURVE)||defined(SIZEOVERLIFETIMECURVESEPERATE)||defined(SIZEOVERLIFETIMERANDOMCURVES)||defined(SIZEOVERLIFETIMERANDOMCURVESSEPERATE)\r\nfloat getCurValueFromGradientFloat(in vec2 gradientNumbers[4],in float normalizedAge)\r\n{\r\n\tfloat curValue;\r\n\tfor(int i=1;i<4;i++)\r\n\t{\r\n\t\tvec2 gradientNumber=gradientNumbers[i];\r\n\t\tfloat key=gradientNumber.x;\r\n\t\tif(key>=normalizedAge)\r\n\t\t{\r\n\t\t\tvec2 lastGradientNumber=gradientNumbers[i-1];\r\n\t\t\tfloat lastKey=lastGradientNumber.x;\r\n\t\t\tfloat age=(normalizedAge-lastKey)/(key-lastKey);\r\n\t\t\tcurValue=mix(lastGradientNumber.y,gradientNumber.y,age);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\treturn curValue;\r\n}\r\n#endif\r\n\r\n#if defined(VELOCITYOVERLIFETIMECURVE)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)||defined(ROTATIONOVERLIFETIMECURVE)||defined(ROTATIONOVERLIFETIMERANDOMCURVES)\r\nfloat getTotalValueFromGradientFloat(in vec2 gradientNumbers[4],in float normalizedAge)\r\n{\r\n\tfloat totalValue=0.0;\r\n\tfor(int i=1;i<4;i++)\r\n\t{\r\n\t\tvec2 gradientNumber=gradientNumbers[i];\r\n\t\tfloat key=gradientNumber.x;\r\n\t\tvec2 lastGradientNumber=gradientNumbers[i-1];\r\n\t\tfloat lastValue=lastGradientNumber.y;\r\n\t\t\r\n\t\tif(key>=normalizedAge){\r\n\t\t\tfloat lastKey=lastGradientNumber.x;\r\n\t\t\tfloat age=(normalizedAge-lastKey)/(key-lastKey);\r\n\t\t\ttotalValue+=(lastValue+mix(lastValue,gradientNumber.y,age))/2.0*a_ShapePositionStartLifeTime.w*(normalizedAge-lastKey);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\telse{\r\n\t\t\ttotalValue+=(lastValue+gradientNumber.y)/2.0*a_ShapePositionStartLifeTime.w*(key-lastGradientNumber.x);\r\n\t\t}\r\n\t}\r\n\treturn totalValue;\r\n}\r\n#endif\r\n\r\n#if defined(COLOROVERLIFETIME)||defined(RANDOMCOLOROVERLIFETIME)\r\nvec4 getColorFromGradient(in vec2 gradientAlphas[4],in vec4 gradientColors[4],in float normalizedAge)\r\n{\r\n\tvec4 overTimeColor;\r\n\tfor(int i=1;i<4;i++)\r\n\t{\r\n\t\tvec2 gradientAlpha=gradientAlphas[i];\r\n\t\tfloat alphaKey=gradientAlpha.x;\r\n\t\tif(alphaKey>=normalizedAge)\r\n\t\t{\r\n\t\t\tvec2 lastGradientAlpha=gradientAlphas[i-1];\r\n\t\t\tfloat lastAlphaKey=lastGradientAlpha.x;\r\n\t\t\tfloat age=(normalizedAge-lastAlphaKey)/(alphaKey-lastAlphaKey);\r\n\t\t\toverTimeColor.a=mix(lastGradientAlpha.y,gradientAlpha.y,age);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\t\r\n\tfor(int i=1;i<4;i++)\r\n\t{\r\n\t\tvec4 gradientColor=gradientColors[i];\r\n\t\tfloat colorKey=gradientColor.x;\r\n\t\tif(colorKey>=normalizedAge)\r\n\t\t{\r\n\t\t\tvec4 lastGradientColor=gradientColors[i-1];\r\n\t\t\tfloat lastColorKey=lastGradientColor.x;\r\n\t\t\tfloat age=(normalizedAge-lastColorKey)/(colorKey-lastColorKey);\r\n\t\t\toverTimeColor.rgb=mix(gradientColors[i-1].yzw,gradientColor.yzw,age);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\treturn overTimeColor;\r\n}\r\n#endif\r\n\r\n\r\n#if defined(TEXTURESHEETANIMATIONCURVE)||defined(TEXTURESHEETANIMATIONRANDOMCURVE)\r\nfloat getFrameFromGradient(in vec2 gradientFrames[4],in float normalizedAge)\r\n{\r\n\tfloat overTimeFrame;\r\n\tfor(int i=1;i<4;i++)\r\n\t{\r\n\t\tvec2 gradientFrame=gradientFrames[i];\r\n\t\tfloat key=gradientFrame.x;\r\n\t\tif(key>=normalizedAge)\r\n\t\t{\r\n\t\t\tvec2 lastGradientFrame=gradientFrames[i-1];\r\n\t\t\tfloat lastKey=lastGradientFrame.x;\r\n\t\t\tfloat age=(normalizedAge-lastKey)/(key-lastKey);\r\n\t\t\toverTimeFrame=mix(lastGradientFrame.y,gradientFrame.y,age);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\treturn floor(overTimeFrame);\r\n}\r\n#endif\r\n\r\n#if defined(VELOCITYOVERLIFETIMECONSTANT)||defined(VELOCITYOVERLIFETIMECURVE)||defined(VELOCITYOVERLIFETIMERANDOMCONSTANT)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)\r\nvec3 computeParticleLifeVelocity(in float normalizedAge)\r\n{\r\n vec3 outLifeVelocity;\r\n #ifdef VELOCITYOVERLIFETIMECONSTANT\r\n\t outLifeVelocity=u_VOLVelocityConst; \r\n #endif\r\n #ifdef VELOCITYOVERLIFETIMECURVE\r\n outLifeVelocity= vec3(getCurValueFromGradientFloat(u_VOLVelocityGradientX,normalizedAge),getCurValueFromGradientFloat(u_VOLVelocityGradientY,normalizedAge),getCurValueFromGradientFloat(u_VOLVelocityGradientZ,normalizedAge));\r\n #endif\r\n #ifdef VELOCITYOVERLIFETIMERANDOMCONSTANT\r\n\t outLifeVelocity=mix(u_VOLVelocityConst,u_VOLVelocityConstMax,vec3(a_Random1.y,a_Random1.z,a_Random1.w)); \r\n #endif\r\n #ifdef VELOCITYOVERLIFETIMERANDOMCURVE\r\n outLifeVelocity=vec3(mix(getCurValueFromGradientFloat(u_VOLVelocityGradientX,normalizedAge),getCurValueFromGradientFloat(u_VOLVelocityGradientMaxX,normalizedAge),a_Random1.y),\r\n\t mix(getCurValueFromGradientFloat(u_VOLVelocityGradientY,normalizedAge),getCurValueFromGradientFloat(u_VOLVelocityGradientMaxY,normalizedAge),a_Random1.z),\r\n\t\t\t\t\t mix(getCurValueFromGradientFloat(u_VOLVelocityGradientZ,normalizedAge),getCurValueFromGradientFloat(u_VOLVelocityGradientMaxZ,normalizedAge),a_Random1.w));\r\n #endif\r\n\t\t\t\t\t\r\n return outLifeVelocity;\r\n} \r\n#endif\r\n\r\nvec3 computeParticlePosition(in vec3 startVelocity, in vec3 lifeVelocity,in float age,in float normalizedAge,vec3 gravityVelocity,vec4 worldRotation)\r\n{\r\n vec3 startPosition;\r\n vec3 lifePosition;\r\n #if defined(VELOCITYOVERLIFETIMECONSTANT)||defined(VELOCITYOVERLIFETIMECURVE)||defined(VELOCITYOVERLIFETIMERANDOMCONSTANT)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)\r\n\t#ifdef VELOCITYOVERLIFETIMECONSTANT\r\n\t\t startPosition=startVelocity*age;\r\n\t\t lifePosition=lifeVelocity*age;\r\n\t#endif\r\n\t#ifdef VELOCITYOVERLIFETIMECURVE\r\n\t\t startPosition=startVelocity*age;\r\n\t\t lifePosition=vec3(getTotalValueFromGradientFloat(u_VOLVelocityGradientX,normalizedAge),getTotalValueFromGradientFloat(u_VOLVelocityGradientY,normalizedAge),getTotalValueFromGradientFloat(u_VOLVelocityGradientZ,normalizedAge));\r\n\t#endif\r\n\t#ifdef VELOCITYOVERLIFETIMERANDOMCONSTANT\r\n\t\t startPosition=startVelocity*age;\r\n\t\t lifePosition=lifeVelocity*age;\r\n\t#endif\r\n\t#ifdef VELOCITYOVERLIFETIMERANDOMCURVE\r\n\t\t startPosition=startVelocity*age;\r\n\t\t lifePosition=vec3(mix(getTotalValueFromGradientFloat(u_VOLVelocityGradientX,normalizedAge),getTotalValueFromGradientFloat(u_VOLVelocityGradientMaxX,normalizedAge),a_Random1.y)\r\n\t ,mix(getTotalValueFromGradientFloat(u_VOLVelocityGradientY,normalizedAge),getTotalValueFromGradientFloat(u_VOLVelocityGradientMaxY,normalizedAge),a_Random1.z)\r\n\t ,mix(getTotalValueFromGradientFloat(u_VOLVelocityGradientZ,normalizedAge),getTotalValueFromGradientFloat(u_VOLVelocityGradientMaxZ,normalizedAge),a_Random1.w));\r\n\t#endif\r\n\t\r\n\tvec3 finalPosition;\r\n\tif(u_VOLSpaceType==0){\r\n\t if(u_ScalingMode!=2)\r\n\t finalPosition =rotationByQuaternions(u_PositionScale*(a_ShapePositionStartLifeTime.xyz+startPosition+lifePosition),worldRotation);\r\n\t else\r\n\t finalPosition =rotationByQuaternions(u_PositionScale*a_ShapePositionStartLifeTime.xyz+startPosition+lifePosition,worldRotation);\r\n\t}\r\n\telse{\r\n\t if(u_ScalingMode!=2)\r\n\t finalPosition = rotationByQuaternions(u_PositionScale*(a_ShapePositionStartLifeTime.xyz+startPosition),worldRotation)+lifePosition;\r\n\t else\r\n\t finalPosition = rotationByQuaternions(u_PositionScale*a_ShapePositionStartLifeTime.xyz+startPosition,worldRotation)+lifePosition;\r\n\t}\r\n #else\r\n\t startPosition=startVelocity*age;\r\n\t vec3 finalPosition;\r\n\t if(u_ScalingMode!=2)\r\n\t\t\tfinalPosition = rotationByQuaternions(u_PositionScale*(a_ShapePositionStartLifeTime.xyz+startPosition),worldRotation);\r\n\t else\r\n\t \tfinalPosition = rotationByQuaternions(u_PositionScale*a_ShapePositionStartLifeTime.xyz+startPosition,worldRotation);\r\n #endif\r\n \r\n if(u_SimulationSpace==0)\r\n finalPosition=finalPosition+a_SimulationWorldPostion;\r\n else if(u_SimulationSpace==1) \r\n finalPosition=finalPosition+u_WorldPosition;\r\n \r\n finalPosition+=0.5*gravityVelocity*age;\r\n \r\n return finalPosition;\r\n}\r\n\r\n\r\nvec4 computeParticleColor(in vec4 color,in float normalizedAge)\r\n{\r\n\t#ifdef COLOROVERLIFETIME\r\n\t color*=getColorFromGradient(u_ColorOverLifeGradientAlphas,u_ColorOverLifeGradientColors,normalizedAge);\r\n\t#endif\r\n\t\r\n\t#ifdef RANDOMCOLOROVERLIFETIME\r\n\t color*=mix(getColorFromGradient(u_ColorOverLifeGradientAlphas,u_ColorOverLifeGradientColors,normalizedAge),getColorFromGradient(u_MaxColorOverLifeGradientAlphas,u_MaxColorOverLifeGradientColors,normalizedAge),a_Random0.y);\r\n\t#endif\r\n\r\n return color;\r\n}\r\n\r\nvec2 computeParticleSizeBillbard(in vec2 size,in float normalizedAge)\r\n{\r\n\t#ifdef SIZEOVERLIFETIMECURVE\r\n\t\tsize*=getCurValueFromGradientFloat(u_SOLSizeGradient,normalizedAge);\r\n\t#endif\r\n\t#ifdef SIZEOVERLIFETIMERANDOMCURVES\r\n\t size*=mix(getCurValueFromGradientFloat(u_SOLSizeGradient,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientMax,normalizedAge),a_Random0.z); \r\n\t#endif\r\n\t#ifdef SIZEOVERLIFETIMECURVESEPERATE\r\n\t\tsize*=vec2(getCurValueFromGradientFloat(u_SOLSizeGradientX,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientY,normalizedAge));\r\n\t#endif\r\n\t#ifdef SIZEOVERLIFETIMERANDOMCURVESSEPERATE\r\n\t size*=vec2(mix(getCurValueFromGradientFloat(u_SOLSizeGradientX,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientMaxX,normalizedAge),a_Random0.z)\r\n\t ,mix(getCurValueFromGradientFloat(u_SOLSizeGradientY,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientMaxY,normalizedAge),a_Random0.z));\r\n\t#endif\r\n\treturn size;\r\n}\r\n\r\n#ifdef RENDERMODE_MESH\r\nvec3 computeParticleSizeMesh(in vec3 size,in float normalizedAge)\r\n{\r\n\t#ifdef SIZEOVERLIFETIMECURVE\r\n\t\tsize*=getCurValueFromGradientFloat(u_SOLSizeGradient,normalizedAge);\r\n\t#endif\r\n\t#ifdef SIZEOVERLIFETIMERANDOMCURVES\r\n\t size*=mix(getCurValueFromGradientFloat(u_SOLSizeGradient,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientMax,normalizedAge),a_Random0.z); \r\n\t#endif\r\n\t#ifdef SIZEOVERLIFETIMECURVESEPERATE\r\n\t\tsize*=vec3(getCurValueFromGradientFloat(u_SOLSizeGradientX,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientY,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientZ,normalizedAge));\r\n\t#endif\r\n\t#ifdef SIZEOVERLIFETIMERANDOMCURVESSEPERATE\r\n\t size*=vec3(mix(getCurValueFromGradientFloat(u_SOLSizeGradientX,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientMaxX,normalizedAge),a_Random0.z)\r\n\t ,mix(getCurValueFromGradientFloat(u_SOLSizeGradientY,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientMaxY,normalizedAge),a_Random0.z)\r\n\t\t,mix(getCurValueFromGradientFloat(u_SOLSizeGradientZ,normalizedAge),getCurValueFromGradientFloat(u_SOLSizeGradientMaxZ,normalizedAge),a_Random0.z));\r\n\t#endif\r\n\treturn size;\r\n}\r\n#endif\r\n\r\nfloat computeParticleRotationFloat(in float rotation,in float age,in float normalizedAge)\r\n{ \r\n\t#ifdef ROTATIONOVERLIFETIME\r\n\t\t#ifdef ROTATIONOVERLIFETIMECONSTANT\r\n\t\t\tfloat ageRot=u_ROLAngularVelocityConst*age;\r\n\t rotation+=ageRot;\r\n\t\t#endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMECURVE\r\n\t\t\trotation+=getTotalValueFromGradientFloat(u_ROLAngularVelocityGradient,normalizedAge);\r\n\t\t#endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMERANDOMCONSTANTS\r\n\t\t\tfloat ageRot=mix(u_ROLAngularVelocityConst,u_ROLAngularVelocityConstMax,a_Random0.w)*age;\r\n\t rotation+=ageRot;\r\n\t #endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMERANDOMCURVES\r\n\t\t\trotation+=mix(getTotalValueFromGradientFloat(u_ROLAngularVelocityGradient,normalizedAge),getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientMax,normalizedAge),a_Random0.w);\r\n\t\t#endif\r\n\t#endif\r\n\t#ifdef ROTATIONOVERLIFETIMESEPERATE\r\n\t\t#ifdef ROTATIONOVERLIFETIMECONSTANT\r\n\t\t\tfloat ageRot=u_ROLAngularVelocityConstSeprarate.z*age;\r\n\t rotation+=ageRot;\r\n\t\t#endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMECURVE\r\n\t\t\trotation+=getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientZ,normalizedAge);\r\n\t\t#endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMERANDOMCONSTANTS\r\n\t\t\tfloat ageRot=mix(u_ROLAngularVelocityConstSeprarate.z,u_ROLAngularVelocityConstMaxSeprarate.z,a_Random0.w)*age;\r\n\t rotation+=ageRot;\r\n\t #endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMERANDOMCURVES\r\n\t\t\trotation+=mix(getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientZ,normalizedAge),getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientMaxZ,normalizedAge),a_Random0.w));\r\n\t\t#endif\r\n\t#endif\r\n\treturn rotation;\r\n}\r\n\r\n#if defined(RENDERMODE_MESH)&&(defined(ROTATIONOVERLIFETIME)||defined(ROTATIONOVERLIFETIMESEPERATE))\r\nvec3 computeParticleRotationVec3(in vec3 rotation,in float age,in float normalizedAge)\r\n{ \r\n\t#ifdef ROTATIONOVERLIFETIME\r\n\t#ifdef ROTATIONOVERLIFETIMECONSTANT\r\n\t\t\tfloat ageRot=u_ROLAngularVelocityConst*age;\r\n\t rotation+=ageRot;\r\n\t\t#endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMECURVE\r\n\t\t\trotation+=getTotalValueFromGradientFloat(u_ROLAngularVelocityGradient,normalizedAge);\r\n\t\t#endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMERANDOMCONSTANTS\r\n\t\t\tfloat ageRot=mix(u_ROLAngularVelocityConst,u_ROLAngularVelocityConstMax,a_Random0.w)*age;\r\n\t rotation+=ageRot;\r\n\t #endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMERANDOMCURVES\r\n\t\t\trotation+=mix(getTotalValueFromGradientFloat(u_ROLAngularVelocityGradient,normalizedAge),getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientMax,normalizedAge),a_Random0.w);\r\n\t\t#endif\r\n\t#endif\r\n\t#ifdef ROTATIONOVERLIFETIMESEPERATE\r\n\t\t#ifdef ROTATIONOVERLIFETIMECONSTANT\r\n\t\t\tvec3 ageRot=u_ROLAngularVelocityConstSeprarate*age;\r\n\t rotation+=ageRot;\r\n\t\t#endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMECURVE\r\n\t\t\trotation+=vec3(getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientX,normalizedAge),getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientY,normalizedAge),getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientZ,normalizedAge));\r\n\t\t#endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMERANDOMCONSTANTS\r\n\t\t\tvec3 ageRot=mix(u_ROLAngularVelocityConstSeprarate,u_ROLAngularVelocityConstMaxSeprarate,a_Random0.w)*age;\r\n\t rotation+=ageRot;\r\n\t #endif\r\n\t\t#ifdef ROTATIONOVERLIFETIMERANDOMCURVES\r\n\t\t\trotation+=vec3(mix(getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientX,normalizedAge),getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientMaxX,normalizedAge),a_Random0.w)\r\n\t ,mix(getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientY,normalizedAge),getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientMaxY,normalizedAge),a_Random0.w)\r\n\t ,mix(getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientZ,normalizedAge),getTotalValueFromGradientFloat(u_ROLAngularVelocityGradientMaxZ,normalizedAge),a_Random0.w));\r\n\t\t#endif\r\n\t#endif\r\n\treturn rotation;\r\n}\r\n#endif\r\n\r\nvec2 computeParticleUV(in vec2 uv,in float normalizedAge)\r\n{ \r\n\t#ifdef TEXTURESHEETANIMATIONCURVE\r\n\t\tfloat cycleNormalizedAge=normalizedAge*u_TSACycles;\r\n\t\tfloat frame=getFrameFromGradient(u_TSAGradientUVs,cycleNormalizedAge-floor(cycleNormalizedAge));\r\n\t\tfloat totalULength=frame*u_TSASubUVLength.x;\r\n\t\tfloat floorTotalULength=floor(totalULength);\r\n\t uv.x+=totalULength-floorTotalULength;\r\n\t\tuv.y+=floorTotalULength*u_TSASubUVLength.y;\r\n #endif\r\n\t#ifdef TEXTURESHEETANIMATIONRANDOMCURVE\r\n\t\tfloat cycleNormalizedAge=normalizedAge*u_TSACycles;\r\n\t\tfloat uvNormalizedAge=cycleNormalizedAge-floor(cycleNormalizedAge);\r\n\t float frame=floor(mix(getFrameFromGradient(u_TSAGradientUVs,uvNormalizedAge),getFrameFromGradient(u_TSAMaxGradientUVs,uvNormalizedAge),a_Random1.x));\r\n\t\tfloat totalULength=frame*u_TSASubUVLength.x;\r\n\t\tfloat floorTotalULength=floor(totalULength);\r\n\t uv.x+=totalULength-floorTotalULength;\r\n\t\tuv.y+=floorTotalULength*u_TSASubUVLength.y;\r\n #endif\r\n\treturn uv;\r\n}\r\n\r\nvoid main()\r\n{\r\n\tfloat age = u_CurrentTime - a_DirectionTime.w;\r\n\tfloat normalizedAge = age/a_ShapePositionStartLifeTime.w;\r\n\tvec3 lifeVelocity;\r\n\tif(normalizedAge<1.0)\r\n\t{ \r\n\t\tvec3 startVelocity=a_DirectionTime.xyz*a_StartSpeed;\r\n\t\t#if defined(VELOCITYOVERLIFETIMECONSTANT)||defined(VELOCITYOVERLIFETIMECURVE)||defined(VELOCITYOVERLIFETIMERANDOMCONSTANT)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)\r\n\t\t\tlifeVelocity= computeParticleLifeVelocity(normalizedAge);//计算粒子生命周期速度\r\n\t\t#endif \r\n\t\tvec3 gravityVelocity=u_Gravity*age;\r\n\t\t\r\n\t\tvec4 worldRotation;\r\n\t\tif(u_SimulationSpace==0)\r\n\t\t\tworldRotation=a_SimulationWorldRotation;\r\n\t\telse\r\n\t\t\tworldRotation=u_WorldRotation;\r\n\t\t\r\n\t\tvec3 center=computeParticlePosition(startVelocity, lifeVelocity, age, normalizedAge,gravityVelocity,worldRotation);//计算粒子位置\r\n\t\r\n\t\r\n\t\t#ifdef SPHERHBILLBOARD\r\n\t\t\tvec2 corner=a_CornerTextureCoordinate.xy;//Billboard模式z轴无效\r\n\t\t\tvec3 cameraUpVector =normalize(u_CameraUp);//TODO:是否外面归一化\r\n\t\t\tvec3 sideVector = normalize(cross(u_CameraDirection,cameraUpVector));\r\n\t\t\tvec3 upVector = normalize(cross(sideVector,u_CameraDirection));\r\n\t\t\tcorner*=computeParticleSizeBillbard(a_StartSize.xy,normalizedAge);\r\n\t\t\t#if defined(ROTATIONOVERLIFETIME)||defined(ROTATIONOVERLIFETIMESEPERATE)\r\n\t\t\t\tif(u_ThreeDStartRotation){\r\n\t\t\t\t\tvec3 rotation=vec3(a_StartRotation0.xy,computeParticleRotationFloat(a_StartRotation0.z,age,normalizedAge));\r\n\t\t\t\t\tcenter += u_SizeScale.xzy*rotationByEuler(corner.x*sideVector+corner.y*upVector,rotation);\r\n\t\t\t\t}\r\n\t\t\t\telse{\r\n\t\t\t\t\tfloat rot = computeParticleRotationFloat(a_StartRotation0.x, age,normalizedAge);\r\n\t\t\t\t\tfloat c = cos(rot);\r\n\t\t\t\t\tfloat s = sin(rot);\r\n\t\t\t\t\tmat2 rotation= mat2(c, -s, s, c);\r\n\t\t\t\t\tcorner=rotation*corner;\r\n\t\t\t\t\tcenter += u_SizeScale.xzy*(corner.x*sideVector+corner.y*upVector);\r\n\t\t\t\t}\r\n\t\t\t#else\r\n\t\t\t\tif(u_ThreeDStartRotation){\r\n\t\t\t\t\tcenter += u_SizeScale.xzy*rotationByEuler(corner.x*sideVector+corner.y*upVector,a_StartRotation0);\r\n\t\t\t\t}\r\n\t\t\t\telse{\r\n\t\t\t\t\tfloat c = cos(a_StartRotation0.x);\r\n\t\t\t\t\tfloat s = sin(a_StartRotation0.x);\r\n\t\t\t\t\tmat2 rotation= mat2(c, -s, s, c);\r\n\t\t\t\t\tcorner=rotation*corner;\r\n\t\t\t\t\tcenter += u_SizeScale.xzy*(corner.x*sideVector+corner.y*upVector);\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t#endif\r\n\t\r\n\t\t#ifdef STRETCHEDBILLBOARD\r\n\t\t\tvec2 corner=a_CornerTextureCoordinate.xy;//Billboard模式z轴无效\r\n\t\t\tvec3 velocity;\r\n\t\t\t#if defined(VELOCITYOVERLIFETIMECONSTANT)||defined(VELOCITYOVERLIFETIMECURVE)||defined(VELOCITYOVERLIFETIMERANDOMCONSTANT)||defined(VELOCITYOVERLIFETIMERANDOMCURVE)\r\n\t\t\t\tif(u_VOLSpaceType==0)\r\n\t\t\t\tvelocity=rotationByQuaternions(u_SizeScale*(startVelocity+lifeVelocity),worldRotation)+gravityVelocity;\r\n\t\t\t\telse\r\n\t\t\t\tvelocity=rotationByQuaternions(u_SizeScale*startVelocity,worldRotation)+lifeVelocity+gravityVelocity;\r\n\t\t\t#else\r\n\t\t\t\tvelocity= rotationByQuaternions(u_SizeScale*startVelocity,worldRotation)+gravityVelocity;\r\n\t\t\t#endif\t\r\n\t\t\tvec3 cameraUpVector = normalize(velocity);\r\n\t\t\tvec3 direction = normalize(center-u_CameraPos);\r\n\t\t\tvec3 sideVector = normalize(cross(direction,normalize(velocity)));\r\n\t\t\t\r\n\t\t\tsideVector=u_SizeScale.xzy*sideVector;\r\n\t\t\tcameraUpVector=length(vec3(u_SizeScale.x,0.0,0.0))*cameraUpVector;\r\n\t\t\t\r\n\t\t\tvec2 size=computeParticleSizeBillbard(a_StartSize.xy,normalizedAge);\r\n\t\t\t\r\n\t\t\tconst mat2 rotaionZHalfPI=mat2(0.0, -1.0, 1.0, 0.0);\r\n\t\t\tcorner=rotaionZHalfPI*corner;\r\n\t\t\tcorner.y=corner.y-abs(corner.y);\r\n\t\t\t\r\n\t\t\tfloat speed=length(velocity);//TODO:\r\n\t\t\tcenter +=sign(u_SizeScale.x)*(sign(u_StretchedBillboardLengthScale)*size.x*corner.x*sideVector+(speed*u_StretchedBillboardSpeedScale+size.y*u_StretchedBillboardLengthScale)*corner.y*cameraUpVector);\r\n\t\t#endif\r\n\t\r\n\t\t#ifdef HORIZONTALBILLBOARD\r\n\t\t\tvec2 corner=a_CornerTextureCoordinate.xy;//Billboard模式z轴无效\r\n\t\t\tconst vec3 cameraUpVector=vec3(0.0,0.0,1.0);\r\n\t\t\tconst vec3 sideVector = vec3(-1.0,0.0,0.0);\r\n\t\t\t\r\n\t\t\tfloat rot = computeParticleRotationFloat(a_StartRotation0.x, age,normalizedAge);\r\n\t\t\tfloat c = cos(rot);\r\n\t\t\tfloat s = sin(rot);\r\n\t\t\tmat2 rotation= mat2(c, -s, s, c);\r\n\t\t\tcorner=rotation*corner*cos(0.78539816339744830961566084581988);//TODO:临时缩小cos45,不确定U3D原因\r\n\t\t\tcorner*=computeParticleSizeBillbard(a_StartSize.xy,normalizedAge);\r\n\t\t\tcenter +=u_SizeScale.xzy*(corner.x*sideVector+ corner.y*cameraUpVector);\r\n\t\t#endif\r\n\t\r\n\t\t#ifdef VERTICALBILLBOARD\r\n\t\t\tvec2 corner=a_CornerTextureCoordinate.xy;//Billboard模式z轴无效\r\n\t\t\tconst vec3 cameraUpVector =vec3(0.0,1.0,0.0);\r\n\t\t\tvec3 sideVector = normalize(cross(u_CameraDirection,cameraUpVector));\r\n\t\t\t\r\n\t\t\tfloat rot = computeParticleRotationFloat(a_StartRotation0.x, age,normalizedAge);\r\n\t\t\tfloat c = cos(rot);\r\n\t\t\tfloat s = sin(rot);\r\n\t\t\tmat2 rotation= mat2(c, -s, s, c);\r\n\t\t\tcorner=rotation*corner*cos(0.78539816339744830961566084581988);//TODO:临时缩小cos45,不确定U3D原因\r\n\t\t\tcorner*=computeParticleSizeBillbard(a_StartSize.xy,normalizedAge);\r\n\t\t\tcenter +=u_SizeScale.xzy*(corner.x*sideVector+ corner.y*cameraUpVector);\r\n\t\t#endif\r\n\t\r\n\t\t#ifdef RENDERMODE_MESH\r\n\t\t\tvec3 size=computeParticleSizeMesh(a_StartSize,normalizedAge);\r\n\t\t\t#if defined(ROTATIONOVERLIFETIME)||defined(ROTATIONOVERLIFETIMESEPERATE)\r\n\t\t\t\tif(u_ThreeDStartRotation){\r\n\t\t\t\t\tvec3 rotation=vec3(a_StartRotation0.xy,computeParticleRotationFloat(a_StartRotation0.z, age,normalizedAge));\r\n\t\t\t\t\tcenter+= rotationByQuaternions(u_SizeScale*rotationByEuler(a_MeshPosition*size,rotation),worldRotation);\r\n\t\t\t\t}\r\n\t\t\t\telse{\r\n\t\t\t\t\t#ifdef ROTATIONOVERLIFETIME\r\n\t\t\t\t\t\tfloat angle=computeParticleRotationFloat(a_StartRotation0.x, age,normalizedAge);\r\n\t\t\t\t\t\tif(a_ShapePositionStartLifeTime.x!=0.0||a_ShapePositionStartLifeTime.y!=0.0){\r\n\t\t\t\t\t\t\tcenter+= (rotationByQuaternions(rotationByAxis(u_SizeScale*a_MeshPosition*size,normalize(cross(vec3(0.0,0.0,1.0),vec3(a_ShapePositionStartLifeTime.xy,0.0))),angle),worldRotation));//已验证\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse{\r\n\t\t\t\t\t\t\t#ifdef SHAPE\r\n\t\t\t\t\t\t\t\tcenter+= u_SizeScale.xzy*(rotationByQuaternions(rotationByAxis(a_MeshPosition*size,vec3(0.0,-1.0,0.0),angle),worldRotation));\r\n\t\t\t\t\t\t\t#else\r\n\t\t\t\t\t\t\t\tif(u_SimulationSpace==0)\r\n\t\t\t\t\t\t\t\t\tcenter+=rotationByAxis(u_SizeScale*a_MeshPosition*size,vec3(0.0,0.0,-1.0),angle);//已验证\r\n\t\t\t\t\t\t\t\telse if(u_SimulationSpace==1)\r\n\t\t\t\t\t\t\t\t\tcenter+=rotationByQuaternions(u_SizeScale*rotationByAxis(a_MeshPosition*size,vec3(0.0,0.0,-1.0),angle),worldRotation);//已验证\r\n\t\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t#endif\r\n\t\t\t\t\t#ifdef ROTATIONOVERLIFETIMESEPERATE\r\n\t\t\t\t\t\t//TODO:是否应合并if(u_ThreeDStartRotation)分支代码,待测试\r\n\t\t\t\t\t\tvec3 angle=computeParticleRotationVec3(vec3(0.0,0.0,-a_StartRotation0.x), age,normalizedAge);\r\n\t\t\t\t\t\tcenter+= (rotationByQuaternions(rotationByEuler(u_SizeScale*a_MeshPosition*size,vec3(angle.x,angle.y,angle.z)),worldRotation));//已验证\r\n\t\t\t\t\t#endif\t\t\r\n\t\t\t\t}\r\n\t\t\t#else\r\n\t\t\t\tif(u_ThreeDStartRotation){\r\n\t\t\t\t\tcenter+= rotationByQuaternions(u_SizeScale*rotationByEuler(a_MeshPosition*size,a_StartRotation0),worldRotation);//已验证\r\n\t\t\t\t}\r\n\t\t\t\telse{\r\n\t\t\t\t\tif(a_ShapePositionStartLifeTime.x!=0.0||a_ShapePositionStartLifeTime.y!=0.0){\r\n\t\t\t\t\t\tif(u_SimulationSpace==0)\r\n\t\t\t\t\t\t\tcenter+= rotationByAxis(u_SizeScale*a_MeshPosition*size,normalize(cross(vec3(0.0,0.0,1.0),vec3(a_ShapePositionStartLifeTime.xy,0.0))),a_StartRotation0.x);\r\n\t\t\t\t\t\telse if(u_SimulationSpace==1)\r\n\t\t\t\t\t\t\tcenter+= (rotationByQuaternions(u_SizeScale*rotationByAxis(a_MeshPosition*size,normalize(cross(vec3(0.0,0.0,1.0),vec3(a_ShapePositionStartLifeTime.xy,0.0))),a_StartRotation0.x),worldRotation));//已验证\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse{\r\n\t\t\t\t\t\t#ifdef SHAPE\r\n\t\t\t\t\t\t\tif(u_SimulationSpace==0)\r\n\t\t\t\t\t\t\t\tcenter+= u_SizeScale*rotationByAxis(a_MeshPosition*size,vec3(0.0,-1.0,0.0),a_StartRotation0.x);\r\n\t\t\t\t\t\t\telse if(u_SimulationSpace==1)\r\n\t\t\t\t\t\t\t\tcenter+= rotationByQuaternions(u_SizeScale*rotationByAxis(a_MeshPosition*size,vec3(0.0,-1.0,0.0),a_StartRotation0.x),worldRotation);\t\r\n\t\t\t\t\t\t#else\r\n\t\t\t\t\t\t\tif(u_SimulationSpace==0)\r\n\t\t\t\t\t\t\t\tcenter+= rotationByAxis(u_SizeScale*a_MeshPosition*size,vec3(0.0,0.0,-1.0),a_StartRotation0.x);\r\n\t\t\t\t\t\t\telse if(u_SimulationSpace==1)\r\n\t\t\t\t\t\t\t\tcenter+= rotationByQuaternions(u_SizeScale*rotationByAxis(a_MeshPosition*size,vec3(0.0,0.0,-1.0),a_StartRotation0.x),worldRotation);//已验证\r\n\t\t\t\t\t\t#endif\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t\tv_MeshColor=a_MeshColor;\r\n\t\t#endif\r\n\t\r\n\t\tgl_Position=u_Projection*u_View*vec4(center,1.0);\r\n\t\tv_Color = computeParticleColor(a_StartColor, normalizedAge);\r\n\t\t#ifdef DIFFUSEMAP\r\n\t\t\t#if defined(SPHERHBILLBOARD)||defined(STRETCHEDBILLBOARD)||defined(HORIZONTALBILLBOARD)||defined(VERTICALBILLBOARD)\r\n\t\t\t\tv_TextureCoordinate =computeParticleUV(a_CornerTextureCoordinate.zw, normalizedAge);\r\n\t\t\t#endif\r\n\t\t\t#ifdef RENDERMODE_MESH\r\n\t\t\t\tv_TextureCoordinate =computeParticleUV(a_MeshTextureCoordinate, normalizedAge);\r\n\t\t\t#endif\r\n\t\t\t\r\n\t\t\t#ifdef TILINGOFFSET\r\n\t\t\t\tv_TextureCoordinate=TransformUV(v_TextureCoordinate,u_TilingOffset);\r\n\t\t\t#endif\r\n\t\t#endif\r\n \t}\r\n \telse\r\n\t{\r\n\t\tgl_Position=vec4(2.0,2.0,2.0,1.0);//Discard use out of X(-1,1),Y(-1,1),Z(0,1)\r\n\t}\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}\r\n\r\n"; var LayaPBRBRDF = "// allow to explicitly override LAYA_BRDF_GI and LAYA_BRDF_LIGHT in custom shader,default is layaBRDFHighGI and layaBRDFHighLight\r\n#if !defined (LAYA_BRDF_GI) \r\n\t#if defined(LAYA_PBR_BRDF_LOW)\r\n\t\t#define LAYA_BRDF_GI layaBRDFLowGI\r\n\t#elif defined(LAYA_PBR_BRDF_HIGH)\r\n\t\t#define LAYA_BRDF_GI layaBRDFHighGI\r\n\t#endif\r\n#endif\r\n#if !defined (LAYA_BRDF_LIGHT)\r\n\t#if defined(LAYA_PBR_BRDF_LOW)\r\n\t\t#define LAYA_BRDF_LIGHT layaBRDFLowLight\r\n\t#elif defined(LAYA_PBR_BRDF_HIGH)\r\n\t\t#define LAYA_BRDF_LIGHT layaBRDFHighLight\r\n\t#endif\r\n#endif\r\n\r\n#define PI 3.14159265359\r\n#define INV_PI 0.31830988618\r\n\r\nmediump float pow4(mediump float x)\r\n{\r\n\treturn x * x * x * x;\r\n}\r\n\r\nmediump float pow5(mediump float x)\r\n{\r\n\treturn x * x * x * x * x;\r\n}\r\n\r\nmediump vec3 fresnelLerp(mediump vec3 F0,mediump vec3 F90,mediump float cosA)\r\n{\r\n\tfloat t = pow5(1.0 - cosA); // ala Schlick interpoliation\r\n\treturn mix(F0, F90, t);\r\n}\r\n\r\nmediump vec3 fresnelTerm(mediump vec3 F0,mediump float cosA)\r\n{\r\n\tfloat t = pow5(1.0 - cosA); // ala Schlick interpoliation\r\n\treturn F0 + (vec3(1.0) - F0) * t;\r\n}\r\n\r\n// approximage Schlick with ^4 instead of ^5\r\nmediump vec3 fresnelLerpFast (mediump vec3 F0, mediump vec3 F90,mediump float cosA)\r\n{\r\n mediump float t = pow4 (1.0 - cosA);\r\n return mix (F0, F90, t);\r\n}\r\n\r\nfloat smoothnessToPerceptualRoughness(float smoothness)\r\n{\r\n return 1.0 - smoothness;\r\n}\r\n\r\nfloat perceptualRoughnessToRoughness(float perceptualRoughness)\r\n{\r\n return perceptualRoughness * perceptualRoughness;\r\n}\r\n\r\nvec3 safeNormalize(vec3 inVec)\r\n{\r\n\tfloat dp3 = max(0.001,dot(inVec,inVec));\r\n\treturn inVec * inversesqrt(dp3);\r\n}\r\n\r\n// Note: Disney diffuse must be multiply by diffuseAlbedo / PI. This is done outside of this function.\r\nmediump float disneyDiffuse(mediump float NdotV,mediump float NdotL,mediump float LdotH,mediump float perceptualRoughness)\r\n{\r\n\t//https://www.cnblogs.com/herenzhiming/articles/5790389.html\r\n\tmediump float fd90 = 0.5 + 2.0 * LdotH * LdotH * perceptualRoughness;\r\n\t// Two schlick fresnel term\r\n\tmediump float lightScatter = (1.0 + (fd90 - 1.0) * pow5(1.0 - NdotL));\r\n\tmediump float viewScatter = (1.0 + (fd90 - 1.0) * pow5(1.0 - NdotV));\r\n\r\n\treturn lightScatter * viewScatter;\r\n}\r\n\r\n// Ref: http://jcgt.org/published/0003/02/03/paper.pdf\r\nfloat smithJointGGXVisibilityTerm(float NdotL, float NdotV, float roughness)\r\n{\r\n\t// Original formulation:\r\n // lambda_v = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;\r\n // lambda_l = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5f;\r\n // G = 1 / (1 + lambda_v + lambda_l);\r\n\r\n\t// scientific code implement:\r\n\t// Reorder code to be more optimal\r\n // half a = roughness;\r\n // half a2 = a * a;\r\n\r\n // half lambdaV = NdotL * sqrt((-NdotV * a2 + NdotV) * NdotV + a2);\r\n // half lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);\r\n\r\n // Simplify visibility term: (2.0f * NdotL * NdotV) / ((4.0f * NdotL * NdotV) * (lambda_v + lambda_l + 1e-5f));\r\n // return 0.5f / (lambdaV + lambdaL + 1e-5f); \r\n\t// This function is not intended to be running on Mobile,therefore epsilon is smaller than can be represented by half\r\n\r\n\t// Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough)\r\n\tfloat a = roughness;\r\n\tfloat lambdaV = NdotL * (NdotV * (1.0 - a) + a);\r\n\tfloat lambdaL = NdotV * (NdotL * (1.0 - a) + a);\r\n\treturn 0.5 / (lambdaV + lambdaL + 1e-5);\r\n}\r\n\r\nfloat ggxTerm(float NdotH, float roughness)\r\n{\r\n\tfloat a2 = roughness * roughness;\r\n\tfloat d = (NdotH * a2 - NdotH) * NdotH + 1.0; // 2 mad\r\n\treturn INV_PI * a2 / (d * d + 1e-7); // This function is not intended to be running on Mobile,therefore epsilon is smaller than what can be represented by half//返回值小用half来返回\r\n}\r\n\r\n// BRDF1-------------------------------------------------------------------------------------\r\n\r\n// Note: BRDF entry points use smoothness and oneMinusReflectivity for optimization purposes,\r\n// mostly for DX9 SM2.0 level. Most of the math is being done on these (1-x) values, and that saves a few precious ALU slots.\r\n\r\n// Main Physically Based BRDF\r\n// Derived from Disney work and based on Torrance-Sparrow micro-facet model\r\n//\r\n// BRDF = kD / pi + kS * (D * V * F) / 4\r\n// I = BRDF * NdotL\r\n//\r\n// *NDF GGX:\r\n// *Smith for Visiblity term\r\n// *Schlick approximation for Fresnel\r\nmediump vec4 layaBRDFHighLight(mediump vec3 diffColor, mediump vec3 specColor, mediump float oneMinusReflectivity, float perceptualRoughness,float roughness,mediump float nv,vec3 normal, vec3 viewDir,LayaLight light)\r\n{\r\n\tvec3 halfDir = safeNormalize(viewDir-light.dir);\r\n\r\n\tfloat nl = clamp(dot(normal, -light.dir),0.0,1.0);\r\n\tfloat nh = clamp(dot(normal, halfDir),0.0,1.0);\r\n\tmediump float lv = clamp(dot(light.dir, viewDir),0.0,1.0);\r\n\tmediump float lh = clamp(dot(light.dir, -halfDir),0.0,1.0);\r\n\r\n\t// Diffuse term\r\n\tmediump float diffuseTerm = disneyDiffuse(nv, nl, lh, perceptualRoughness) * nl;\r\n\r\n\t// Specular term\r\n // HACK: theoretically we should divide diffuseTerm by Pi and not multiply specularTerm!\r\n // BUT that will make shader look significantly darker than Legacy ones\r\n\r\n\t// GGX with roughtness to 0 would mean no specular at all, using max(roughness, 0.002) here to match HDrenderloop roughtness remapping.\r\n\troughness = max(roughness, 0.002);\r\n\tfloat V = smithJointGGXVisibilityTerm(nl, nv, roughness);\r\n\tfloat D = ggxTerm(nh, roughness);\r\n\r\n\tfloat specularTerm = V * D * PI; // Torrance-Sparrow model, Fresnel is applied later\r\n\r\n\t//#ifdef LAYA_COLORSPACE_GAMMA\r\n\tspecularTerm = sqrt(max(1e-4, specularTerm));\r\n\t//#endif\r\n\tspecularTerm = max(0.0, specularTerm * nl);\r\n\t\t\r\n\tmediump vec3 color = diffColor * light.color * diffuseTerm + specularTerm * light.color * fresnelTerm(specColor, lh);\r\n\treturn vec4(color, 1.0);\r\n}\r\n\r\nvec4 layaBRDFHighGI(mediump vec3 diffColor,mediump vec3 specColor,mediump float oneMinusReflectivity,float smoothness ,float perceptualRoughness,float roughness,mediump float nv,vec3 normal, vec3 viewDir,LayaGI gi)\r\n{\r\n\t// surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(roughness^2+1)\r\n\tfloat surfaceReduction;\r\n\tsurfaceReduction = 1.0 - 0.28*roughness*perceptualRoughness;// 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1]\r\n\tfloat grazingTerm = clamp(smoothness + (1.0 - oneMinusReflectivity),0.0,1.0);\r\n\tmediump vec3 color =diffColor * gi.diffuse + surfaceReduction * gi.specular * fresnelLerp(specColor,vec3(grazingTerm), nv);\r\n\treturn vec4(color,1.0);\r\n}\r\n// BRDF1-------------------------------------------------------------------------------------\r\n\r\n\r\n// BRDF2-------------------------------------------------------------------------------------\r\n// Based on Minimalist CookTorrance BRDF\r\n// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255\r\n//\r\n// *NDF [Modified] GGX:\r\n// *Modified Kelemen and Szirmay-​Kalos for Visibility term\r\n// *Fresnel approximated with 1/LdotH\r\nmediump vec4 layaBRDFLowLight (mediump vec3 diffColor, mediump vec3 specColor,mediump float oneMinusReflectivity,float perceptualRoughness,float roughness,mediump float nv,vec3 normal,vec3 viewDir,LayaLight light)\r\n{\r\n vec3 halfDir = safeNormalize (viewDir-light.dir);\r\n mediump float nl = clamp(dot(normal, -light.dir),0.0,1.0);\r\n float nh = clamp(dot(normal, halfDir),0.0,1.0);\r\n float lh = clamp(dot(-light.dir, halfDir),0.0,1.0);\r\n\r\n // GGX Distribution multiplied by combined approximation of Visibility and Fresnel\r\n // See \"Optimizing PBR for Mobile\" from Siggraph 2015 moving mobile graphics course\r\n // https://community.arm.com/events/1155\r\n mediump float a = roughness;\r\n float a2 = a*a;\r\n\r\n float d = nh * nh * (a2 - 1.0) + 1.00001;\r\n\t// #ifdef LAYA_COLORSPACE_GAMMA\r\n\t\t// Tighter approximation for Gamma only rendering mode!\r\n\t\t// DVF = sqrt(DVF);\r\n\t\t// DVF = (a * sqrt(.25)) / (max(sqrt(0.1), lh)*sqrt(roughness + .5) * d);\r\n\t\tfloat specularTerm = a / (max(0.32, lh) * (1.5 + roughness) * d);\r\n\t// #else\r\n\t// \tfloat specularTerm = a2 / (max(0.1f, lh*lh) * (roughness + 0.5f) * (d * d) * 4);\r\n\t// #endif\r\n\r\n // on mobiles (where half actually means something) denominator have risk of overflow\r\n // clamp below was added specifically to \"fix\" that, but dx compiler (we convert bytecode to metal/gles)\r\n // sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))\r\n\r\n\t//#if defined (SHADER_API_MOBILE)\r\n specularTerm = specularTerm - 1e-4;\r\n\t//#endif\r\n\r\n\t// #else\r\n\t\t// // Legacy\r\n\t\t// half specularPower = PerceptualRoughnessToSpecPower(perceptualRoughness);\r\n\t\t// // Modified with approximate Visibility function that takes roughness into account\r\n\t\t// // Original ((n+1)*N.H^n) / (8*Pi * L.H^3) didn't take into account roughness\r\n\t\t// // and produced extremely bright specular at grazing angles\r\n\r\n\t\t// half invV = lh * lh * smoothness + perceptualRoughness * perceptualRoughness; // approx ModifiedKelemenVisibilityTerm(lh, perceptualRoughness);\r\n\t\t// half invF = lh;\r\n\r\n\t\t// half specularTerm = ((specularPower + 1) * pow (nh, specularPower)) / (8 * invV * invF + 1e-4h);\r\n\r\n\t\t// #ifdef LAYA_COLORSPACE_GAMMA\r\n\t\t// \tspecularTerm = sqrt(max(1e-4f, specularTerm));\r\n\t\t// #endif\r\n\t// #endif\r\n\r\n\t// #if defined (SHADER_API_MOBILE)\r\n\t\tspecularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles\r\n\t// #endif\r\n \r\n mediump vec3 color = (diffColor + specularTerm * specColor) * light.color * nl;\r\n\r\n return vec4(color, 1.0);\r\n}\r\n\r\nmediump vec4 layaBRDFLowGI (mediump vec3 diffColor, mediump vec3 specColor,mediump float oneMinusReflectivity,mediump float smoothness,float perceptualRoughness,float roughness,mediump float nv,vec3 normal,vec3 viewDir,LayaGI gi)\r\n{\r\n\t// surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(realRoughness^2+1)\r\n\r\n // 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1]\r\n // 1-x^3*(0.6-0.08*x) approximation for 1/(x^4+1)\r\n\t// #ifdef LAYA_COLORSPACE_GAMMA\r\n\t\tmediump float surfaceReduction = 0.28;\r\n\t// #else\r\n\t\t// mediump float surfaceReduction = (0.6-0.08*perceptualRoughness);\r\n\t// #endif\r\n\r\n surfaceReduction = 1.0 - roughness*perceptualRoughness*surfaceReduction;\r\n\r\n\tmediump float grazingTerm = clamp(smoothness + (1.0-oneMinusReflectivity),0.0,1.0);\r\n\tmediump vec3 color =gi.diffuse * diffColor+ surfaceReduction * gi.specular * fresnelLerpFast (specColor, vec3(grazingTerm), nv);\r\n\r\n return vec4(color, 1.0);\r\n}\r\n// BRDF2-------------------------------------------------------------------------------------"; var PBRCore = "struct FragmentCommonData{\r\n\tvec3 diffColor;\r\n\tvec3 specColor;\r\n\tfloat oneMinusReflectivity;\r\n\tfloat smoothness;\r\n\t//vec3 eyeVec;TODO:maybe can remove\r\n\t//float alpha;\r\n\t//vec3 reflUVW;\r\n};\r\n\r\n#ifndef SETUP_BRDF_INPUT\r\n #define SETUP_BRDF_INPUT metallicSetup//default is metallicSetup,also can be other. \r\n#endif\r\n\r\nconst mediump vec4 dielectricSpecularColor = vec4(0.220916301, 0.220916301, 0.220916301, 1.0 - 0.220916301);\r\n\r\nmediump vec3 diffuseAndSpecularFromMetallic(mediump vec3 albedo,mediump float metallic, out mediump vec3 specColor, out mediump float oneMinusReflectivity)\r\n{\r\n\tspecColor = mix(dielectricSpecularColor.rgb, albedo, metallic);\r\n\toneMinusReflectivity= dielectricSpecularColor.a*(1.0-metallic);//diffuse proportion\r\n\treturn albedo * oneMinusReflectivity;\r\n}\r\n\r\nmediump float specularStrength(mediump vec3 specular)\r\n{\r\n return max (max (specular.r, specular.g), specular.b);\r\n}\r\n\r\n// Diffuse/Spec Energy conservation\r\nmediump vec3 energyConservationBetweenDiffuseAndSpecular (mediump vec3 albedo, mediump vec3 specColor, out mediump float oneMinusReflectivity)\r\n{\r\n\toneMinusReflectivity = 1.0 - specularStrength(specColor);\r\n return albedo * (vec3(1.0) - specColor);\r\n}\r\n\r\n#ifdef TRANSPARENTBLEND\r\n\tmediump vec3 preMultiplyAlpha (mediump vec3 diffColor, mediump float alpha, mediump float oneMinusReflectivity,out mediump float modifiedAlpha)\r\n\t{\r\n\t\t// Transparency 'removes' from Diffuse component\r\n\t\tdiffColor *= alpha;\r\n\t\t// Reflectivity 'removes' from the rest of components, including Transparency\r\n\t\t// modifiedAlpha = 1.0-(1.0-alpha)*(1.0-reflectivity) = 1.0-(oneMinusReflectivity - alpha*oneMinusReflectivity) = 1.0-oneMinusReflectivity + alpha*oneMinusReflectivity\r\n\t\tmodifiedAlpha = 1.0 - oneMinusReflectivity + alpha*oneMinusReflectivity;\r\n\t\treturn diffColor;\r\n\t}\r\n#endif\r\n\r\nFragmentCommonData metallicSetup(vec2 uv)\r\n{\r\n\tmediump vec2 metallicGloss = getMetallicGloss(uv);\r\n\tmediump float metallic = metallicGloss.x;\r\n\tmediump float smoothness = metallicGloss.y; // this is 1 minus the square root of real roughness m.\r\n\tmediump float oneMinusReflectivity;\r\n\tmediump vec3 specColor;\r\n\tmediump vec3 diffColor = diffuseAndSpecularFromMetallic(albedo(uv), metallic,/*out*/specColor,/*out*/oneMinusReflectivity);\r\n\r\n\tFragmentCommonData o;\r\n\to.diffColor = diffColor;\r\n\to.specColor = specColor;\r\n\to.oneMinusReflectivity = oneMinusReflectivity;\r\n\to.smoothness = smoothness;\r\n\treturn o;\r\n}\r\n\r\nFragmentCommonData specularSetup(vec2 uv)\r\n{\r\n mediump vec4 specGloss = specularGloss(uv);\r\n mediump vec3 specColor = specGloss.rgb;\r\n mediump float smoothness = specGloss.a;\r\n\r\n mediump float oneMinusReflectivity;\r\n mediump vec3 diffColor = energyConservationBetweenDiffuseAndSpecular (albedo(uv), specColor, /*out*/ oneMinusReflectivity);\r\n\r\n FragmentCommonData o;\r\n o.diffColor = diffColor;\r\n o.specColor = specColor;\r\n o.oneMinusReflectivity = oneMinusReflectivity;\r\n o.smoothness = smoothness;\r\n return o;\r\n}\r\n\r\nLayaGI fragmentGI(float smoothness,vec3 eyeVec,mediump float occlusion,mediump vec2 lightmapUV,vec3 worldnormal)\r\n{\r\n\tLayaGIInput giInput;\r\n\t#ifdef LIGHTMAP\r\n\t\tgiInput.lightmapUV=lightmapUV;\r\n\t#endif\r\n\r\n\tvec3 worldViewDir = -eyeVec;\r\n\tmediump vec4 uvwRoughness;\r\n\tuvwRoughness.rgb = reflect(worldViewDir, worldnormal);//reflectUVW\r\n\tuvwRoughness.a= smoothnessToPerceptualRoughness(smoothness);//perceptualRoughness\r\n\r\n\treturn layaGlobalIllumination(giInput,occlusion, worldnormal, uvwRoughness);\r\n}\r\n\r\n\r\nvec3 perPixelWorldNormal(vec2 uv,vec3 normal,vec3 binormal,vec3 tangent)\r\n{\r\n\t#ifdef NORMALTEXTURE\r\n\t\tmediump vec3 normalTangent=normalInTangentSpace(uv);\r\n\t\tvec3 normalWorld = normalize(tangent * normalTangent.x + binormal * normalTangent.y + normal * normalTangent.z);\r\n\t#else\r\n\t\tvec3 normalWorld = normalize(normal);\r\n\t#endif\r\n\t\treturn normalWorld;\r\n}\r\n\r\nvoid fragmentForward()\r\n{\r\n\tvec2 uv;\r\n\t#if defined(ALBEDOTEXTURE)||defined(METALLICGLOSSTEXTURE)||defined(NORMALTEXTURE)||defined(EMISSIONTEXTURE)||defined(OCCLUSIONTEXTURE)||defined(PARALLAXTEXTURE)\r\n\t\t#ifdef PARALLAXTEXTURE\r\n\t\t\tuv = parallax(v_Texcoord0,normalize(v_ViewDirForParallax));\r\n\t\t#else\r\n\t\t\tuv = v_Texcoord0;\r\n\t\t#endif\r\n\t#endif\r\n\r\n\tmediump float alpha = getAlpha(uv);\r\n\t#ifdef ALPHATEST\r\n\t\tif(alpha= u_DirationLightCount)\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t#ifdef CALCULATE_SHADOWS\r\n\t\t\t\t\tif(i == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t#ifdef SHADOW_CASCADE\r\n\t\t\t\t\t\t\tvec4 shadowCoord = getShadowCoord(vec4(v_PositionWorld,1.0));\r\n\t\t\t\t\t\t#else\r\n\t\t\t\t\t\t\tvec4 shadowCoord = v_ShadowCoord;\r\n\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\tshadowAttenuation *= sampleShadowmap(shadowCoord);\r\n\t\t\t\t\t}\r\n\t\t\t\t#endif\r\n\t\t\t\tDirectionLight directionLight = getDirectionLight(u_LightBuffer,i);\r\n\t\t\t\tLayaLight dirLight = layaDirectionLightToLight(directionLight,shadowAttenuation);\r\n\t\t\t \tcolor+=LAYA_BRDF_LIGHT(o.diffColor,o.specColor,o.oneMinusReflectivity,perceptualRoughness,roughness,nv,normalWorld,eyeVec,dirLight);\r\n\t\t\t}\r\n\t \t#endif\r\n\t\t#if defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t\t\tivec4 clusterInfo =getClusterInfo(u_LightClusterBuffer,u_View,u_Viewport, v_PositionWorld,gl_FragCoord,u_ProjectionParams);\r\n\t\t\t#ifdef POINTLIGHT\r\n\t\t\t\tfor (int i = 0; i < MAX_LIGHT_COUNT; i++) \r\n\t\t\t\t{\r\n\t\t\t\t\tshadowAttenuation = 1.0;\r\n\t\t\t\t\tif(i >= clusterInfo.x)//PointLightCount\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tPointLight pointLight = getPointLight(u_LightBuffer,u_LightClusterBuffer,clusterInfo,i);\r\n\t\t\t\t\tLayaLight poiLight = layaPointLightToLight(posworld,normalWorld,pointLight,shadowAttenuation);\r\n\t\t\t\t\tcolor+= LAYA_BRDF_LIGHT(o.diffColor,o.specColor,o.oneMinusReflectivity,perceptualRoughness,roughness,nv,normalWorld,eyeVec,poiLight);\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t\t#ifdef SPOTLIGHT\r\n\t\t\t\tfor (int i = 0; i < MAX_LIGHT_COUNT; i++) \r\n\t\t\t\t{\r\n\t\t\t\t\tshadowAttenuation = 1.0;\r\n\t\t\t\t\tif(i >= clusterInfo.y)//SpotLightCount\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t#ifdef CALCULATE_SPOTSHADOWS\r\n\t\t\t\t\t\tif(i == 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tvec4 spotShadowcoord = v_SpotShadowCoord;\r\n\t\t\t\t\t\t\tshadowAttenuation= sampleSpotShadowmap(spotShadowcoord);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t#endif\r\n\t\t\t\t\tSpotLight spotLight = getSpotLight(u_LightBuffer,u_LightClusterBuffer,clusterInfo,i);\r\n\t\t\t\t\tLayaLight spoLight = layaSpotLightToLight(posworld,normalWorld,spotLight,shadowAttenuation);\r\n\t\t\t\t\tcolor+= LAYA_BRDF_LIGHT(o.diffColor,o.specColor,o.oneMinusReflectivity,perceptualRoughness,roughness,nv,normalWorld,eyeVec,spoLight);\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t#endif\r\n\t #endif\r\n\r\n\t#ifdef EMISSION\r\n\t\tcolor.rgb += emission(uv);\r\n\t#endif\r\n\r\n\t#ifdef FOG\r\n\t\tfloat lerpFact=clamp((1.0/gl_FragCoord.w-u_FogStart)/u_FogRange,0.0,1.0);\r\n\t\tcolor.rgb=mix(color.rgb,u_FogColor,lerpFact);\r\n\t#endif\r\n\t\r\n\tgl_FragColor=vec4(color.rgb,alpha);\r\n}\r\n\r\n\r\n"; var PBRVSInput = "attribute vec4 a_Position;\r\n\r\n#ifdef GPU_INSTANCE\r\n\tattribute mat4 a_MvpMatrix;\r\n\tattribute mat4 a_WorldMat;\r\n#else\r\n\tuniform mat4 u_MvpMatrix;\r\n\tuniform mat4 u_WorldMat;\r\n#endif\r\n\r\n#ifdef BONE\r\n\tconst int c_MaxBoneCount = 24;\r\n\tattribute vec4 a_BoneIndices;\r\n\tattribute vec4 a_BoneWeights;\r\n\tuniform mat4 u_Bones[c_MaxBoneCount];\r\n#endif\r\n\r\nattribute vec3 a_Normal;\r\nvarying vec3 v_Normal; \r\n\r\n#if defined(NORMALTEXTURE)||defined(PARALLAXTEXTURE)\r\n\tattribute vec4 a_Tangent0;\r\n\tvarying vec3 v_Tangent;\r\n\tvarying vec3 v_Binormal;\r\n #ifdef PARALLAXTEXTURE\r\n\t varying vec3 v_ViewDirForParallax;\r\n #endif\r\n#endif\r\n\r\n#if defined(ALBEDOTEXTURE)||defined(METALLICGLOSSTEXTURE)||defined(NORMALTEXTURE)||defined(EMISSIONTEXTURE)||defined(OCCLUSIONTEXTURE)||defined(PARALLAXTEXTURE)||(defined(LIGHTMAP)&&defined(UV))\r\n\tattribute vec2 a_Texcoord0;\r\n\tvarying vec2 v_Texcoord0;\r\n#endif\r\n\r\n#if defined(LIGHTMAP)&&defined(UV1)\r\n\tattribute vec2 a_Texcoord1;\r\n#endif\r\n\r\n#ifdef LIGHTMAP\r\n\tuniform vec4 u_LightmapScaleOffset;\r\n\tvarying vec2 v_LightMapUV;\r\n#endif\r\n\r\nuniform vec3 u_CameraPos;\r\nvarying vec3 v_EyeVec;\r\nvarying vec3 v_PositionWorld;\r\nvarying float v_posViewZ;\r\n\r\n#if defined(CALCULATE_SHADOWS)&&!defined(SHADOW_CASCADE)\r\n\tvarying vec4 v_ShadowCoord;\r\n#endif\r\n\r\n#ifdef CALCULATE_SPOTSHADOWS\r\n\tvarying vec4 v_SpotShadowCoord;\r\n#endif\r\n\r\n#ifdef TILINGOFFSET\r\n\tuniform vec4 u_TilingOffset;\r\n#endif"; var PBRFSInput = "#ifdef ALPHATEST\r\n\tuniform float u_AlphaTestValue;\r\n#endif\r\n\r\nuniform vec4 u_AlbedoColor;\r\n\r\n#ifdef NORMALTEXTURE\r\n\tuniform sampler2D u_NormalTexture;\r\n\tuniform float u_NormalScale;\r\n#endif\r\n\r\n#ifdef ALBEDOTEXTURE\r\n\tuniform sampler2D u_AlbedoTexture;\r\n#endif\r\n\r\n#ifdef METALLICGLOSSTEXTURE\r\n\tuniform sampler2D u_MetallicGlossTexture;\r\n#endif\r\nuniform float u_Metallic;\r\n\r\n#ifdef SPECULARGLOSSTEXTURE\r\n\tuniform sampler2D u_SpecGlossTexture;\r\n#endif\r\nuniform vec3 u_SpecularColor;\r\n\r\nuniform float u_Smoothness;\r\nuniform float u_SmoothnessScale;\r\n\r\n#ifdef PARALLAXTEXTURE\r\n\tuniform sampler2D u_ParallaxTexture;\r\n\tuniform float u_ParallaxScale;\r\n\tvarying vec3 v_ViewDirForParallax;\r\n#endif\r\n\r\n#ifdef OCCLUSIONTEXTURE\r\n\tuniform sampler2D u_OcclusionTexture;\r\n\tuniform float u_occlusionStrength;\r\n#endif\r\n\r\n#ifdef EMISSION \r\n\t#ifdef EMISSIONTEXTURE\r\n\t\tuniform sampler2D u_EmissionTexture;\r\n\t#endif\r\n\tuniform vec4 u_EmissionColor;\r\n#endif\r\n\r\n#if defined(ALBEDOTEXTURE)||defined(METALLICGLOSSTEXTURE)||defined(NORMALTEXTURE)||defined(EMISSIONTEXTURE)||defined(OCCLUSIONTEXTURE)||defined(PARALLAXTEXTURE)\r\n\tvarying vec2 v_Texcoord0;\r\n#endif\r\n\r\n#ifdef LIGHTMAP\r\n\tvarying vec2 v_LightMapUV;\r\n\tuniform sampler2D u_LightMap;\r\n\t#ifdef LIGHTMAP_DIRECTIONAL\r\n\t\tuniform sampler2D u_LightMapDirection;\r\n\t#endif\r\n#endif\r\n\r\nvarying vec3 v_Normal; \r\n\r\n#if defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT)\r\n\t#ifdef LEGACYSINGLELIGHTING\r\n\t\t#ifdef DIRECTIONLIGHT\r\n\t\t\tuniform DirectionLight u_DirectionLight;\r\n\t\t#endif\r\n\t\t#ifdef POINTLIGHT\r\n\t\t\tuniform PointLight u_PointLight;\r\n\t\t#endif\r\n\t\t#ifdef SPOTLIGHT\r\n\t\t\tuniform SpotLight u_SpotLight;\r\n\t\t#endif\r\n\t#else\r\n\t\tuniform mat4 u_View;\r\n\t\tuniform vec4 u_ProjectionParams;\r\n\t\tuniform vec4 u_Viewport;\r\n\t\tuniform int u_DirationLightCount;\r\n\t\tuniform sampler2D u_LightBuffer;\r\n\t\tuniform sampler2D u_LightClusterBuffer;\r\n\t#endif\r\n#endif\r\n\r\nvarying vec3 v_EyeVec;\r\n\r\n#ifdef NORMALTEXTURE\r\n\tvarying vec3 v_Tangent;\r\n\tvarying vec3 v_Binormal;\r\n#endif\r\n\r\n#ifdef FOG\r\n\tuniform float u_FogStart;\r\n\tuniform float u_FogRange;\r\n\tuniform vec3 u_FogColor;\r\n#endif\r\n\r\n\r\n//后面考虑宏TODO\r\nvarying vec3 v_PositionWorld;\r\n\r\n#if defined(CALCULATE_SHADOWS)&&!defined(SHADOW_CASCADE)\r\n\tvarying vec4 v_ShadowCoord;\r\n#endif\r\n\r\n#ifdef CALCULATE_SPOTSHADOWS\r\n\tvarying vec4 v_SpotShadowCoord;\r\n#endif\r\n\r\nmediump float lerpOneTo(mediump float b, mediump float t)\r\n{\r\n mediump float oneMinusT = 1.0 - t;\r\n return oneMinusT + b * t;\r\n}\r\n\r\n#ifdef EMISSION \r\n\tvec3 emission(vec2 uv)\r\n\t{\r\n\t\t#ifdef EMISSIONTEXTURE\r\n\t\t\treturn texture2D(u_EmissionTexture, uv).rgb * u_EmissionColor.rgb;\r\n\t\t#else\r\n\t\t\treturn u_EmissionColor.rgb;\r\n\t\t#endif\r\n\t}\r\n#endif\r\n\r\nmediump float getAlpha(vec2 uv)\r\n{\r\n\t#ifdef SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA\r\n\t\treturn u_AlbedoColor.a;\r\n\t#else\r\n\t\t#ifdef ALBEDOTEXTURE\r\n\t\t\treturn texture2D(u_AlbedoTexture, uv).a * u_AlbedoColor.a;\r\n\t\t#else\r\n\t\t\treturn u_AlbedoColor.a;\r\n\t\t#endif\r\n\t#endif\r\n}\r\n\r\nmediump float getOcclusion(vec2 uv)\r\n{\r\n\t#ifdef OCCLUSIONTEXTURE\r\n\t\tmediump float occ = texture2D(u_OcclusionTexture, uv).g;\r\n\t\treturn lerpOneTo(occ, u_occlusionStrength);\r\n\t#else\r\n\t\treturn 1.0;\r\n\t#endif\r\n}\r\n\r\nmediump vec3 albedo(vec2 uv)\r\n{\r\n\t#ifdef ALBEDOTEXTURE\r\n\t\treturn u_AlbedoColor.rgb * texture2D(u_AlbedoTexture, uv).rgb;\r\n\t#else\r\n\t\treturn u_AlbedoColor.rgb;\r\n\t#endif\r\n\t//TODO:Detail Texture\r\n}\r\n\r\nmediump vec2 getMetallicGloss(vec2 uv)\r\n{\r\n\tmediump vec2 ms;//x is metallic,y is smoothness\r\n\t#ifdef METALLICGLOSSTEXTURE\r\n\t\t#ifdef SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA\r\n\t\t\tms.x = texture2D(u_MetallicGlossTexture, uv).r;\r\n\t\t\t#ifdef ALBEDOTEXTURE\r\n\t\t\t\tms.y = texture2D(u_AlbedoTexture, uv).a*u_SmoothnessScale;\r\n\t\t\t#else\r\n\t\t\t\tms.y = u_SmoothnessScale;\r\n\t\t\t#endif\r\n\t\t#else\r\n\t\t\tms = texture2D(u_MetallicGlossTexture, uv).ra;\r\n\t\t\tms.y *= u_SmoothnessScale;\r\n\t\t#endif\r\n\t#else\r\n\t\tms.x = u_Metallic;\r\n\t\t#ifdef SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA\r\n\t\t\t#ifdef ALBEDOTEXTURE\r\n\t\t\t\tms.y = texture2D(u_AlbedoTexture, uv).a * u_SmoothnessScale;\r\n\t\t\t#else\r\n\t\t\t\tms.y = u_SmoothnessScale;\r\n\t\t\t#endif\r\n\t\t#else\r\n\t\t\tms.y = u_Smoothness;\r\n\t\t#endif\r\n\t#endif\r\n\treturn ms;\r\n}\r\n\r\nmediump vec4 specularGloss(vec2 uv)\r\n{\r\n\tmediump vec4 sg;\r\n\t#ifdef SPECULARGLOSSTEXTURE\r\n\t\t#ifdef SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA\r\n\t\t\tsg.rgb = texture2D(u_SpecGlossTexture, uv).rgb;\r\n\t\t\t#ifdef ALBEDOTEXTURE\r\n\t\t\t\tsg.a = texture2D(u_AlbedoTexture, uv).a*u_SmoothnessScale;\r\n\t\t\t#else\r\n\t\t\t\tsg.a = u_SmoothnessScale;\r\n\t\t\t#endif\r\n\t\t#else\r\n\t\t\tsg = texture2D(u_SpecGlossTexture, uv);\r\n\t\t\tsg.a *= u_SmoothnessScale;\r\n\t\t#endif\r\n\t#else\r\n\t\tsg.rgb = u_SpecularColor.rgb;\r\n\t\t#ifdef SMOOTHNESSSOURCE_ALBEDOTEXTURE_ALPHA\r\n\t\t\t#ifdef ALBEDOTEXTURE\r\n\t\t\t\tsg.a = texture2D(u_AlbedoTexture, uv).a * u_SmoothnessScale;\r\n\t\t\t#else\r\n\t\t\t\tsg.a = u_SmoothnessScale;\r\n\t\t\t#endif\r\n\t\t#else\r\n\t\t\tsg.a = u_Smoothness;\r\n\t\t#endif\r\n\t#endif\r\n\t\treturn sg;\r\n}\r\n\r\n\r\n#ifdef NORMALTEXTURE\r\n\tmediump vec3 unpackScaleNormal(mediump vec3 packednormal, mediump float bumpScale)\r\n\t{\r\n\t\tmediump vec3 normal = packednormal.xyz * 2.0 - 1.0;\r\n\t\tnormal.y=-normal.y;//NOTE:because unity to LayaAir coordSystem.\r\n\t\tnormal.xy *= bumpScale;\r\n\t\treturn normal;\r\n\t}\r\n\t\r\n\tmediump vec3 normalInTangentSpace(vec2 texcoords)\r\n\t{\r\n\t\tmediump vec3 normalTangent = unpackScaleNormal(texture2D(u_NormalTexture, texcoords).rgb,u_NormalScale);\r\n\t\treturn normalTangent;\r\n\t}\r\n#endif\r\n\r\n#ifdef PARALLAXTEXTURE\r\n\tmediump vec2 parallaxOffset1Step(mediump float h, mediump float height, mediump vec3 viewDir)\r\n\t{\r\n\t\th = h * height - height / 2.0;\r\n\t\tviewDir.z += 0.42;\r\n\t\treturn h * (viewDir.xy / viewDir.z);\r\n\t}\r\n\r\n\tvec2 parallax(vec2 texcoords, mediump vec3 viewDir)\r\n\t{\r\n\t\tmediump float h = texture2D(u_ParallaxTexture, texcoords.xy).g;\r\n\t\tvec2 offset = parallaxOffset1Step(h, u_ParallaxScale, viewDir);\r\n\t\treturn texcoords+offset;\r\n\t}\r\n#endif\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"; var PBRVertex = "vec2 transformLightMapUV(in vec2 texcoord,in vec4 lightmapScaleOffset)\r\n{\r\n\tvec2 lightMapUV=vec2(texcoord.x,1.0-texcoord.y)*lightmapScaleOffset.xy+lightmapScaleOffset.zw;\r\n\tlightMapUV.y=1.0-lightMapUV.y;\r\n\treturn lightMapUV; \r\n}\r\n\r\nvoid vertexForward()\r\n{\r\n\tvec4 position;\r\n\t#ifdef BONE\r\n\t\tmat4 skinTransform = u_Bones[int(a_BoneIndices.x)] * a_BoneWeights.x;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.y)] * a_BoneWeights.y;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.z)] * a_BoneWeights.z;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.w)] * a_BoneWeights.w;\r\n\t\tposition=skinTransform*a_Position;\r\n\t#else\r\n\t\tposition=a_Position;\r\n\t#endif\r\n\r\n\t#ifdef GPU_INSTANCE\r\n\t\tgl_Position = a_MvpMatrix * position;\r\n\t#else\r\n\t\tgl_Position = u_MvpMatrix * position;\r\n\t#endif\r\n\r\n\tmat4 worldMat;\r\n\t#ifdef GPU_INSTANCE\r\n\t\tworldMat = a_WorldMat;\r\n\t#else\r\n\t\tworldMat = u_WorldMat;\r\n\t#endif\r\n\r\n\tv_PositionWorld=(worldMat*position).xyz;\r\n\r\n\t#if defined(ALBEDOTEXTURE)||defined(METALLICGLOSSTEXTURE)||defined(NORMALTEXTURE)||defined(EMISSIONTEXTURE)||defined(OCCLUSIONTEXTURE)||defined(PARALLAXTEXTURE)\r\n\t\t#ifdef TILINGOFFSET\r\n\t\t\tv_Texcoord0=TransformUV(a_Texcoord0,u_TilingOffset);\r\n\t\t#else\r\n\t\t\tv_Texcoord0=a_Texcoord0;\r\n\t\t#endif\r\n\t#endif\r\n\r\n\tv_EyeVec =u_CameraPos-v_PositionWorld;//will normalize per-pixel\r\n\r\n\t#ifdef LIGHTMAP\r\n\t\tvec2 texcoord;\r\n\t\t#ifdef UV1\r\n\t\t\ttexcoord=a_Texcoord1;\r\n\t\t#else\r\n\t\t\ttexcoord=a_Texcoord0;\r\n\t\t#endif\r\n\t\tv_LightMapUV=transformLightMapUV(texcoord,u_LightmapScaleOffset);\r\n\t#endif\r\n\r\n\tmat3 worldInvMat;\r\n\t#ifdef BONE\r\n\t\tworldInvMat=INVERSE_MAT(mat3(worldMat*skinTransform));\r\n\t#else\r\n\t\tworldInvMat=INVERSE_MAT(mat3(worldMat));\r\n\t#endif\r\n\r\n\tv_Normal=normalize(a_Normal*worldInvMat);//if no normalize will cause precision problem.\r\n\r\n\t#ifdef NORMALTEXTURE\r\n\t\tv_Tangent=normalize(a_Tangent0.xyz*worldInvMat);\r\n\t\tv_Binormal=cross(v_Normal,v_Tangent)*a_Tangent0.w;\r\n\t#endif\r\n\r\n\t#ifdef PARALLAXTEXTURE\r\n\t\tvec3 binormal = cross(a_Normal, a_Tangent0.xyz)*a_Tangent0.w;\r\n\t\tmat3 objectTBN = mat3(a_Tangent0.xyz, binormal, a_Normal);\r\n\t\tv_ViewDirForParallax=(worldInvMat*u_CameraPos-position.xyz)*objectTBN;\r\n\t#endif\r\n\r\n\t#if defined(CALCULATE_SHADOWS)&&!defined(SHADOW_CASCADE)\r\n\t\tv_ShadowCoord = getShadowCoord(vec4(v_PositionWorld,1.0));\r\n\t#endif\r\n\r\n\t#ifdef CALCULATE_SPOTSHADOWS\r\n\t\tv_SpotShadowCoord = u_SpotViewProjectMatrix*vec4(positionWS,1.0);\r\n\t#endif\r\n}"; var BloomVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_PositionTexcoord;\r\nvarying vec2 v_Texcoord0;\r\n\r\nvoid main() {\r\n\tgl_Position = vec4(a_PositionTexcoord.xy, 0.0, 1.0);\r\n\tv_Texcoord0 = a_PositionTexcoord.zw;\r\n\tgl_Position = remapGLPositionZ(gl_Position);\r\n}"; var BloomDownsample13PS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Colors.glsl\";\r\n#include \"Sampling.glsl\";\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\nuniform sampler2D u_MainTex;\r\nuniform vec4 u_MainTex_TexelSize;\r\n\r\nvoid fragDownsample13() {\r\n\tmediump vec4 color = downsampleBox13Tap(u_MainTex, v_Texcoord0, u_MainTex_TexelSize.xy);\r\n\tgl_FragColor = color;\r\n}\r\n\r\nvoid main() {\r\n\tfragDownsample13();\r\n}"; var BloomDownsample4PS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Colors.glsl\";\r\n#include \"Sampling.glsl\";\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\nuniform sampler2D u_MainTex;\r\nuniform vec4 u_MainTex_TexelSize;\r\n\r\nvoid fragDownsample4() {\r\n\tmediump vec4 color = downsampleBox4Tap(u_MainTex, v_Texcoord0, u_MainTex_TexelSize.xy);\r\n\tgl_FragColor = color;\r\n}\r\n\r\nvoid main() {\r\n\tfragDownsample4();\r\n}"; var BloomPrefilter13PS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Colors.glsl\";\r\n#include \"Sampling.glsl\";\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\nuniform sampler2D u_MainTex;\r\nuniform sampler2D u_AutoExposureTex;\r\nuniform vec4 u_MainTex_TexelSize;\r\nuniform vec4 u_Threshold; // x: threshold value (linear), y: threshold - knee, z: knee * 2, w: 0.25 / knee\r\nuniform vec4 u_Params; // x: clamp, yzw: unused\r\n\r\nmediump vec4 prefilter(mediump vec4 color, vec2 uv) {\r\n\tmediump float autoExposure = texture2D(u_AutoExposureTex, uv).r;\r\n\tcolor *= autoExposure;\r\n\tcolor = min(vec4(u_Params.x), color); // clamp to max\r\n\tcolor = quadraticThreshold(color, u_Threshold.x, u_Threshold.yzw);\r\n\treturn color;\r\n}\r\n\r\nvoid fragPrefilter13() {\r\n\tmediump vec4 color = downsampleBox13Tap(u_MainTex, v_Texcoord0, u_MainTex_TexelSize.xy);\r\n\tgl_FragColor = prefilter(safeHDR(color), v_Texcoord0);\r\n}\r\n\r\nvoid main() {\r\n\tfragPrefilter13();\r\n}"; var BloomPrefilter4PS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Colors.glsl\";\r\n#include \"Sampling.glsl\";\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\nuniform sampler2D u_MainTex;\r\nuniform sampler2D u_AutoExposureTex;\r\nuniform vec4 u_MainTex_TexelSize;\r\nuniform vec4 u_Threshold; // x: threshold value (linear), y: threshold - knee, z: knee * 2, w: 0.25 / knee\r\nuniform vec4 u_Params; // x: clamp, yzw: unused\r\n\r\nmediump vec4 prefilter(mediump vec4 color, vec2 uv) {\r\n\tmediump float autoExposure = texture2D(u_AutoExposureTex, uv).r;\r\n\tcolor *= autoExposure;\r\n\tcolor = min(vec4(u_Params.x), color); // clamp to max\r\n\tcolor = quadraticThreshold(color, u_Threshold.x, u_Threshold.yzw);\r\n\treturn color;\r\n}\r\n\r\nvoid fragPrefilter4() {\r\n\tmediump vec4 color = downsampleBox4Tap(u_MainTex, v_Texcoord0, u_MainTex_TexelSize.xy);\r\n\tgl_FragColor = prefilter(safeHDR(color), v_Texcoord0);\r\n}\r\n\r\nvoid main() {\r\n\tfragPrefilter4();\r\n}"; var BloomUpsampleBoxPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Colors.glsl\";\r\n#include \"Sampling.glsl\";\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\nuniform sampler2D u_MainTex;\r\nuniform sampler2D u_BloomTex;\r\n\r\nuniform vec4 u_MainTex_TexelSize;\r\nuniform float u_SampleScale;\r\n\r\nmediump vec4 combine(mediump vec4 bloom, vec2 uv) {\r\n\tmediump vec4 color = texture2D(u_BloomTex, uv);\r\n\treturn bloom + color;\r\n}\r\n\r\nvoid fragUpsampleBox() {\r\n\tmediump vec4 bloom = upsampleBox(u_MainTex, v_Texcoord0, u_MainTex_TexelSize.xy, vec4(u_SampleScale));\r\n\tgl_FragColor = combine(bloom, v_Texcoord0);\r\n}\r\n\r\nvoid main() {\r\n\tfragUpsampleBox();\r\n}"; var BloomUpsampleTentPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Colors.glsl\";\r\n#include \"Sampling.glsl\";\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\nuniform sampler2D u_MainTex;\r\nuniform sampler2D u_BloomTex;\r\n\r\nuniform vec4 u_MainTex_TexelSize;\r\nuniform float u_SampleScale;\r\n\r\nmediump vec4 combine(mediump vec4 bloom, vec2 uv) {\r\n\tmediump vec4 color = texture2D(u_BloomTex, uv);\r\n\treturn bloom + color;\r\n}\r\n\r\nvoid fragUpsampleTent() {\r\n\tmediump vec4 bloom = upsampleTent(u_MainTex, v_Texcoord0, u_MainTex_TexelSize.xy, vec4(u_SampleScale));\r\n\tgl_FragColor = combine(bloom, v_Texcoord0);\r\n}\r\n\r\nvoid main() {\r\n\tfragUpsampleTent();\r\n}"; var ColorsGLSL = "#include \"StdLib.glsl\";\r\n\r\n#define EPSILON 1.0e-4\r\n\r\n// Quadratic color thresholding\r\n// curve = (threshold - knee, knee * 2, 0.25 / knee)\r\nmediump vec4 quadraticThreshold(mediump vec4 color, mediump float threshold, mediump vec3 curve) {\r\n\t// Pixel brightness\r\n\tmediump float br = max3(color.r, color.g, color.b);\r\n\r\n\t// Under-threshold part: quadratic curve\r\n\tmediump float rq = clamp(br - curve.x, 0.0, curve.y);\r\n\trq = curve.z * rq * rq;\r\n\r\n\t// Combine and apply the brightness response curve.\r\n\tcolor *= max(rq, br - threshold) / max(br, EPSILON);\r\n\r\n\treturn color;\r\n}\r\n\r\n\r\n\r\n//\r\n// sRGB transfer functions\r\n// Fast path ref: http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1\r\n//\r\nmediump vec3 sRGBToLinear(mediump vec3 c) {\r\n\t#ifdef USE_VERY_FAST_SRGB\r\n\t\treturn c * c;\r\n\t#elif defined(USE_FAST_SRGB)\r\n\t\treturn c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);\r\n\t#else\r\n\t\tmediump vec3 linearRGBLo = c / 12.92;\r\n\t\tmediump vec3 power=vec3(2.4, 2.4, 2.4);\r\n\t\tmediump vec3 linearRGBHi = positivePow((c + 0.055) / 1.055, power);\r\n\t\tmediump vec3 linearRGB =vec3((c.r<=0.04045) ? linearRGBLo.r : linearRGBHi.r,(c.g<=0.04045) ? linearRGBLo.g : linearRGBHi.g,(c.b<=0.04045) ? linearRGBLo.b : linearRGBHi.b);\r\n\t\treturn linearRGB;\r\n\t#endif\r\n}\r\n\r\nmediump vec4 sRGBToLinear(mediump vec4 c){\r\n return vec4(sRGBToLinear(c.rgb), c.a);\r\n}\r\n\r\n\r\n\r\nmediump vec3 linearToSRGB(mediump vec3 c) {\r\n\t#ifdef USE_VERY_FAST_SRGB\r\n\t\treturn sqrt(c);\r\n\t#elif defined(USE_FAST_SRGB)\r\n\t\treturn max(1.055 * PositivePow(c, 0.416666667) - 0.055, 0.0);\r\n\t#else\r\n\t\tmediump vec3 sRGBLo = c * 12.92;\r\n\t\tmediump vec3 power=vec3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4);\r\n\t\tmediump vec3 sRGBHi = (positivePow(c, power) * 1.055) - 0.055;\r\n\t\tmediump vec3 sRGB =vec3((c.r<=0.0031308) ? sRGBLo.r : sRGBHi.r,(c.g<=0.0031308) ? sRGBLo.g : sRGBHi.g,(c.b<=0.0031308) ? sRGBLo.b : sRGBHi.b);\r\n\t\treturn sRGB;\r\n\t#endif\r\n}\r\n\r\nmediump vec4 linearToSRGB(mediump vec4 c){\r\n return vec4(linearToSRGB(c.rgb), c.a);\r\n}"; var CompositePS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Colors.glsl\";\r\n#include \"Sampling.glsl\";\r\n\r\nvarying vec2 v_Texcoord0;\r\n\r\nuniform sampler2D u_MainTex;\r\nuniform sampler2D u_BloomTex;\r\n\r\nuniform sampler2D u_AutoExposureTex;\r\nuniform sampler2D u_Bloom_DirtTex;\r\nuniform vec4 u_BloomTex_TexelSize;\r\nuniform vec4 u_Bloom_DirtTileOffset; // xy: tiling, zw: offset\r\nuniform mediump vec3 u_Bloom_Settings;// x: sampleScale, y: intensity, z: dirt intensity\r\nuniform mediump vec3 u_Bloom_Color;\r\n\r\nvoid main() {\r\n\tmediump float autoExposure = texture2D(u_AutoExposureTex, v_Texcoord0).r;\r\n\tmediump vec4 color=vec4(0.0);\r\n\tcolor = texture2D(u_MainTex, v_Texcoord0);\r\n\t\r\n\tcolor = sRGBToLinear(color);\r\n\tcolor.rgb *= autoExposure;\r\n\t\r\n\t#if defined(BLOOM)||defined(BLOOM_LOW)\r\n\t\t#ifdef BLOOM\r\n\t\t\tmediump vec4 bloom = upsampleTent(u_BloomTex, v_Texcoord0, u_BloomTex_TexelSize.xy, vec4(u_Bloom_Settings.x));\r\n\t\t#else\r\n\t\t\tmediump vec4 bloom = upsampleBox(u_BloomTex, v_Texcoord0, u_BloomTex_TexelSize.xy, vec4(u_Bloom_Settings.x));\r\n\t\t#endif\r\n\r\n\t\t// UVs should be Distort(uv * u_Bloom_DirtTileOffset.xy + u_Bloom_DirtTileOffset.zw)\r\n\t\t// but considering we use a cover-style scale on the dirt texture the difference\r\n\t\t// isn't massive so we chose to save a few ALUs here instead in case lens distortion\r\n\t\t// is active\r\n\t\tmediump vec4 dirt =vec4(texture2D(u_Bloom_DirtTex, v_Texcoord0 * u_Bloom_DirtTileOffset.xy + u_Bloom_DirtTileOffset.zw).rgb, 0.0);\r\n\r\n\t\t// Additive bloom (artist friendly)\r\n\t\tbloom *= u_Bloom_Settings.y;\r\n\t\tdirt *= u_Bloom_Settings.z;\r\n\t\tmediump vec4 bloomColor=vec4(u_Bloom_Color, 1.0);\r\n\t\tcolor += bloom * bloomColor;\r\n\t\tcolor += dirt * bloom;\r\n\t#endif\r\n\t\r\n\tmediump vec4 finalColor = color;\r\n\tfinalColor = linearToSRGB(finalColor);\r\n\t//finalColor.rgb = Dither(finalColor.rgb, v_Texcoord0);//TODO:抖动\r\n\tgl_FragColor = finalColor;\r\n}"; var CompositeVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_PositionTexcoord;\r\nvarying vec2 v_Texcoord0;\r\n\r\nvoid main() {\r\n\tgl_Position = vec4(a_PositionTexcoord.xy, 0.0, 1.0);\r\n\tv_Texcoord0 = a_PositionTexcoord.zw;\r\n\tgl_Position = remapGLPositionZ(gl_Position);\r\n}"; var SamplingGLSL = "// Better, temporally stable box filtering\r\n// [Jimenez14] http://goo.gl/eomGso\r\n// . . . . . . .\r\n// . A . B . C .\r\n// . . D . E . .\r\n// . F . G . H .\r\n// . . I . J . .\r\n// . K . L . M .\r\n// . . . . . . .\r\nmediump vec4 downsampleBox13Tap(sampler2D tex, vec2 uv, vec2 texelSize)\r\n{\r\n mediump vec4 A = texture2D(tex, uv + texelSize * vec2(-1.0, -1.0));\r\n mediump vec4 B = texture2D(tex, uv + texelSize * vec2( 0.0, -1.0));\r\n mediump vec4 C = texture2D(tex, uv + texelSize * vec2( 1.0, -1.0));\r\n mediump vec4 D = texture2D(tex, uv + texelSize * vec2(-0.5, -0.5));\r\n mediump vec4 E = texture2D(tex, uv + texelSize * vec2( 0.5, -0.5));\r\n mediump vec4 F = texture2D(tex, uv + texelSize * vec2(-1.0, 0.0));\r\n mediump vec4 G = texture2D(tex, uv);\r\n mediump vec4 H = texture2D(tex, uv + texelSize * vec2( 1.0, 0.0));\r\n mediump vec4 I = texture2D(tex, uv + texelSize * vec2(-0.5, 0.5));\r\n mediump vec4 J = texture2D(tex, uv + texelSize * vec2( 0.5, 0.5));\r\n mediump vec4 K = texture2D(tex, uv + texelSize * vec2(-1.0, 1.0));\r\n mediump vec4 L = texture2D(tex, uv + texelSize * vec2( 0.0, 1.0));\r\n mediump vec4 M = texture2D(tex, uv + texelSize * vec2( 1.0, 1.0));\r\n\r\n\tmediump vec2 scale= vec2(0.5, 0.125);\r\n mediump vec2 div = (1.0 / 4.0) * scale;\r\n\r\n mediump vec4 o = (D + E + I + J) * div.x;\r\n o += (A + B + G + F) * div.y;\r\n o += (B + C + H + G) * div.y;\r\n o += (F + G + L + K) * div.y;\r\n o += (G + H + M + L) * div.y;\r\n\r\n return o;\r\n}\r\n\r\n// Standard box filtering\r\nmediump vec4 downsampleBox4Tap(sampler2D tex, vec2 uv, vec2 texelSize)\r\n{\r\n vec4 d = texelSize.xyxy * vec4(-1.0, -1.0, 1.0, 1.0);\r\n\r\n mediump vec4 s = texture2D(tex, uv + d.xy);\r\n s += texture2D(tex, uv + d.zy);\r\n s += texture2D(tex, uv + d.xw);\r\n s += texture2D(tex, uv + d.zw);\r\n\r\n return s * (1.0 / 4.0);\r\n}\r\n\r\n// 9-tap bilinear upsampler (tent filter)\r\n// . . . . . . .\r\n// . 1 . 2 . 1 .\r\n// . . . . . . .\r\n// . 2 . 4 . 2 .\r\n// . . . . . . .\r\n// . 1 . 2 . 1 .\r\n// . . . . . . .\r\nmediump vec4 upsampleTent(sampler2D tex, vec2 uv, vec2 texelSize, vec4 sampleScale)\r\n{\r\n vec4 d = texelSize.xyxy * vec4(1.0, 1.0, -1.0, 0.0) * sampleScale;\r\n\r\n mediump vec4 s = texture2D(tex, uv - d.xy);\r\n s += texture2D(tex, uv - d.wy) * 2.0;\r\n s += texture2D(tex, uv - d.zy);\r\n\r\n s += texture2D(tex, uv + d.zw) * 2.0;\r\n s += texture2D(tex, uv) * 4.0;\r\n s += texture2D(tex,\tuv + d.xw) * 2.0;\r\n\r\n s += texture2D(tex, uv + d.zy);\r\n s += texture2D(tex, uv + d.wy) * 2.0;\r\n s += texture2D(tex, uv + d.xy);\r\n\r\n return s * (1.0 / 16.0);\r\n}\r\n\r\n// Standard box filtering\r\nmediump vec4 upsampleBox(sampler2D tex, vec2 uv, vec2 texelSize, vec4 sampleScale)\r\n{\r\n vec4 d = texelSize.xyxy * vec4(-1.0, -1.0, 1.0, 1.0) * 0.5 * sampleScale;\r\n\r\n mediump vec4 s = texture2D(tex, uv + d.xy);\r\n s += texture2D(tex, uv + d.zy);\r\n s += texture2D(tex, uv + d.xw);\r\n s += texture2D(tex, uv + d.zw);\r\n\r\n return s * (1.0 / 4.0);\r\n}"; var StdLibGLSL = "#define HALF_MAX 65504.0 // (2 - 2^-10) * 2^15\r\n\r\n#define FLT_EPSILON 1.192092896e-07 // Smallest positive number, such that 1.0 + FLT_EPSILON != 1.0\r\n\r\nmediump vec4 safeHDR(mediump vec4 c)\r\n{\r\n return min(c, HALF_MAX);\r\n}\r\n\r\nfloat max3(float a, float b, float c)\r\n{\r\n return max(max(a, b), c);\r\n}\r\n\r\nvec3 positivePow(vec3 base, vec3 power)\r\n{\r\n return pow(max(abs(base), vec3(FLT_EPSILON, FLT_EPSILON, FLT_EPSILON)), power);\r\n}"; var ShadowGLSL = "#ifndef GRAPHICS_API_GLES3\r\n\t#define NO_NATIVE_SHADOWMAP\r\n#endif\r\n\r\n#ifdef NO_NATIVE_SHADOWMAP\r\n\t#define TEXTURE2D_SHADOW(textureName) uniform mediump sampler2D textureName\r\n\t#define SAMPLE_TEXTURE2D_SHADOW(textureName, coord3) (texture2D(textureName,coord3.xy).r 3)// out of shadow range cascadeIndex is 4.\r\n\t\t\t\treturn vec4(0.0);\r\n\t\t\t\r\n\t\t\t#ifdef GRAPHICS_API_GLES3\r\n\t\t\t\treturn u_ShadowMatrices[cascadeIndex] * positionWS;\r\n\t\t\t#else\r\n\t\t\t\tmat4 shadowMat;\r\n\t\t\t\tif(cascadeIndex == 0)\r\n\t\t\t\t\tshadowMat = u_ShadowMatrices[0];\r\n\t\t\t\telse if(cascadeIndex == 1)\r\n\t\t\t\t\tshadowMat = u_ShadowMatrices[1];\r\n\t\t\t\telse if(cascadeIndex == 2)\r\n\t\t\t\t\tshadowMat = u_ShadowMatrices[2];\r\n\t\t\t\telse\r\n\t\t\t\t\tshadowMat = u_ShadowMatrices[3];\r\n\t\t\t\treturn shadowMat * positionWS;\r\n\t\t\t#endif\r\n\t\t#else\r\n\t\t\treturn u_ShadowMatrices[0] * positionWS;\r\n\t\t#endif\r\n\t}\r\n\r\n\tfloat sampleShadowmap(vec4 shadowCoord)\r\n\t{\r\n\t\tshadowCoord.xyz /= shadowCoord.w;\r\n\t\tfloat attenuation = 1.0;\r\n\t\tif(shadowCoord.z > 0.0 && shadowCoord.z < 1.0)\r\n\t\t{\r\n\t\t\t#if defined(SHADOW_SOFT_SHADOW_HIGH)\r\n\t\t\t\tattenuation = sampleShdowMapFiltered9(u_ShadowMap,shadowCoord.xyz,u_ShadowMapSize);\r\n\t\t\t#elif defined(SHADOW_SOFT_SHADOW_LOW)\r\n\t\t\t\tattenuation = sampleShdowMapFiltered4(u_ShadowMap,shadowCoord.xyz,u_ShadowMapSize);\r\n\t\t\t#else\r\n\t\t\t\tattenuation = SAMPLE_TEXTURE2D_SHADOW(u_ShadowMap,shadowCoord.xyz);\r\n\t\t\t#endif\r\n\t\t\tattenuation = mix(1.0,attenuation,u_ShadowParams.x);//shadowParams.x:shadow strength\r\n\t\t}\r\n\t\treturn attenuation;\r\n\t}\r\n#endif\r\n\r\n#ifdef CALCULATE_SPOTSHADOWS\r\n\tTEXTURE2D_SHADOW(u_SpotShadowMap);\r\n\tuniform mat4 u_SpotViewProjectMatrix;\r\n\tfloat sampleSpotShadowmap(vec4 shadowCoord)\r\n\t{\r\n\t\tshadowCoord.xyz /= shadowCoord.w;\r\n\t\tfloat attenuation = 1.0;\r\n\t\tshadowCoord.xy +=1.0;\r\n\t\tshadowCoord.xy/=2.0; \r\n\t\tif(shadowCoord.z > 0.0 && shadowCoord.z < 1.0)\r\n\t\t{\r\n\t\t\t#if defined(SHADOW_SPOT_SOFT_SHADOW_HIGH)\r\n\t\t\t\tattenuation = sampleShdowMapFiltered9(u_SpotShadowMap,shadowCoord.xyz,u_ShadowMapSize);\r\n\t\t\t#elif defined(SHADOW_SPOT_SOFT_SHADOW_LOW)\r\n\t\t\t\tattenuation = sampleShdowMapFiltered4(u_SpotShadowMap,shadowCoord.xyz,u_ShadowMapSize);\r\n\t\t\t#else\r\n\t\t\t\tattenuation = SAMPLE_TEXTURE2D_SHADOW(u_SpotShadowMap,shadowCoord.xyz);\r\n\t\t\t#endif\r\n\t\t\tattenuation = mix(1.0,attenuation,u_ShadowParams.y);//shadowParams.y:shadow strength\r\n\t\t}\r\n\t\treturn attenuation;\r\n\t}\r\n#endif\r\n\r\nvec3 applyShadowBias(vec3 positionWS, vec3 normalWS, vec3 lightDirection)\r\n{\r\n float invNdotL = 1.0 - clamp(dot(-lightDirection, normalWS),0.0,1.0);\r\n float scale = invNdotL * u_ShadowBias.y;\r\n\r\n // normal bias is negative since we want to apply an inset normal offset\r\n positionWS += -lightDirection * u_ShadowBias.xxx;\r\n positionWS += normalWS * vec3(scale);\r\n return positionWS;\r\n}\r\n"; var ShadowCasterVSGLSL = "#include \"Lighting.glsl\";\r\n#include \"Shadow.glsl\"\r\n\r\nattribute vec4 a_Position;\r\nattribute vec3 a_Normal;\r\n\r\n#ifdef BONE\r\n\tconst int c_MaxBoneCount = 24;\r\n\tattribute vec4 a_BoneIndices;\r\n\tattribute vec4 a_BoneWeights;\r\n\tuniform mat4 u_Bones[c_MaxBoneCount];\r\n#endif\r\n\r\n#ifdef GPU_INSTANCE\r\n\tattribute mat4 a_WorldMat;\r\n#else\r\n\tuniform mat4 u_WorldMat;\r\n#endif\r\n\r\nuniform mat4 u_ViewProjection;\r\n\r\n#ifdef SHADOW\r\n\tuniform vec3 u_ShadowLightDirection;\r\n#endif\r\n\r\n\r\n\r\n#if defined(DIFFUSEMAP)||((defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT))&&(defined(SPECULARMAP)||defined(NORMALMAP)))||(defined(LIGHTMAP)&&defined(UV))\r\n\tattribute vec2 a_Texcoord0;\r\n\tvarying vec2 v_Texcoord0;\r\n#endif\r\n\r\nvec4 shadowCasterVertex()\r\n{\r\n\tmat4 worldMat;\r\n\t#ifdef GPU_INSTANCE\r\n\t\tworldMat = a_WorldMat;\r\n\t#else\r\n\t\tworldMat = u_WorldMat;\r\n\t#endif\r\n\t\r\n\t#ifdef BONE\r\n\t\tmat4 skinTransform = u_Bones[int(a_BoneIndices.x)] * a_BoneWeights.x;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.y)] * a_BoneWeights.y;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.z)] * a_BoneWeights.z;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.w)] * a_BoneWeights.w;\r\n\t\tworldMat = worldMat * skinTransform;\r\n\t#endif\r\n\r\n\tvec4 positionWS = worldMat * a_Position;\r\n\tvec3 normalWS = normalize(a_Normal*INVERSE_MAT(mat3(worldMat)));//if no normalize will cause precision problem\r\n\r\n\t#ifdef SHADOW\r\n\t\tpositionWS.xyz = applyShadowBias(positionWS.xyz,normalWS,u_ShadowLightDirection);\r\n\t#endif\r\n\r\n\tvec4 positionCS = u_ViewProjection * positionWS;\r\n\t#ifdef SHADOW_SPOT\r\n\t\tpositionCS.z = positionCS.z-u_ShadowBias.x/positionCS.w;\r\n\t#endif\r\n\tpositionCS.z = max(positionCS.z, 0.0);//min ndc z is 0.0\r\n\t\r\n\t// //TODO没考虑UV动画呢\r\n\t// #if defined(DIFFUSEMAP)&&defined(ALPHATEST)\r\n\t// \tv_Texcoord0=a_Texcoord0;\r\n\t// #endif\r\n return positionCS;\r\n}\r\n"; var ShadowCasterFSGLSL = "// #ifdef ALPHATEST\r\n// \tuniform float u_AlphaTestValue;\r\n// #endif\r\n\r\n// #ifdef DIFFUSEMAP\r\n// \tuniform sampler2D u_DiffuseTexture;\r\n// #endif\r\n\r\n// #if defined(DIFFUSEMAP)||((defined(DIRECTIONLIGHT)||defined(POINTLIGHT)||defined(SPOTLIGHT))&&(defined(SPECULARMAP)||defined(NORMALMAP)))\r\n// \tvarying vec2 v_Texcoord0;\r\n// #endif\r\n\r\nvec4 shadowCasterFragment()\r\n{\r\n return vec4(0.0);\r\n // #if defined(DIFFUSEMAP)&&defined(ALPHATEST)\r\n\t// \tfloat alpha = texture2D(u_DiffuseTexture,v_Texcoord0).w;\r\n\t// \tif( alpha < u_AlphaTestValue )\r\n\t// \t{\r\n\t// \t\tdiscard;\r\n\t// \t}\r\n\t// #endif\r\n}\r\n"; var SkyBoxPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\nprecision highp float;\r\n#else\r\nprecision mediump float;\r\n#endif\r\n\r\nvarying vec3 v_Texcoord;\r\n\r\nuniform samplerCube u_CubeTexture;\r\nuniform float u_Exposure;\r\nuniform vec4 u_TintColor;\r\n\r\n\r\nvoid main()\r\n{\t\r\n\tvec3 color=textureCube(u_CubeTexture, v_Texcoord).rgb*u_TintColor.rgb*u_Exposure*2.0;\r\n\tgl_FragColor=vec4(color,1.0);\r\n}\r\n\r\n"; var SkyBoxVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_Position;\r\nuniform mat4 u_ViewProjection;\r\nuniform float u_Rotation;\r\nvarying vec3 v_Texcoord;\r\n\r\n\r\nvec4 rotateAroundYInDegrees (vec4 vertex, float degrees)\r\n{\r\n\tfloat angle = degrees * 3.141593 / 180.0;\r\n\tfloat sina=sin(angle);\r\n\tfloat cosa=cos(angle);\r\n\tmat2 m = mat2(cosa, -sina, sina, cosa);\r\n\treturn vec4(m*vertex.xz, vertex.yw).xzyw;\r\n}\r\n\t\t\r\nvoid main()\r\n{\r\n\tvec4 position=rotateAroundYInDegrees(a_Position,u_Rotation);\r\n\tgl_Position = u_ViewProjection*position;\r\n\tv_Texcoord=vec3(-a_Position.x,a_Position.yz);//转换坐标系\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}\r\n"; var SkyBoxProceduralPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Lighting.glsl\";\r\n\r\nconst float MIE_G = -0.990;\r\nconst float MIE_G2 = 0.9801;\r\nconst float SKY_GROUND_THRESHOLD = 0.02;\r\n\r\nuniform float u_SunSize;\r\nuniform float u_SunSizeConvergence;\r\nuniform DirectionLight u_SunLight;\r\n\r\n\r\nvarying vec3 v_GroundColor;\r\nvarying vec3 v_SkyColor;\r\n\r\n\r\n#ifdef SUN_HIGH_QUALITY\r\n\tvarying vec3 v_Vertex;\r\n#elif defined(SUN_SIMPLE)\r\n\tvarying vec3 v_RayDir;\r\n#else\r\n\tvarying float v_SkyGroundFactor;\r\n#endif\r\n\r\n#if defined(SUN_HIGH_QUALITY)||defined(SUN_SIMPLE)\r\n\tvarying vec3 v_SunColor;\r\n#endif\r\n\r\n// Calculates the Mie phase function\r\nfloat getMiePhase(float eyeCos, float eyeCos2) {\r\n\tfloat temp = 1.0 + MIE_G2 - 2.0 * MIE_G * eyeCos;\r\n\ttemp = pow(temp, pow(u_SunSize,0.65) * 10.0);\r\n\ttemp = max(temp,1.0e-4); // prevent division by zero, esp. in half precision\r\n\ttemp = 1.5 * ((1.0 - MIE_G2) / (2.0 + MIE_G2)) * (1.0 + eyeCos2) / temp;\r\n\treturn temp;\r\n}\r\n\r\n// Calculates the sun shape\r\nfloat calcSunAttenuation(vec3 lightPos, vec3 ray) {\r\n\t#ifdef SUN_HIGH_QUALITY\r\n\t\tfloat focusedEyeCos = pow(clamp(dot(lightPos, ray),0.0,1.0), u_SunSizeConvergence);\r\n\t\treturn getMiePhase(-focusedEyeCos, focusedEyeCos * focusedEyeCos);\r\n\t#else //SUN_SIMPLE\r\n\t\tvec3 delta = lightPos - ray;\r\n\t\tfloat dist = length(delta);\r\n\t\tfloat spot = 1.0 - smoothstep(0.0, u_SunSize, dist);\r\n\t\treturn spot * spot;\r\n\t#endif\r\n}\r\n\r\nvoid main() {\r\n\t// if y > 1 [eyeRay.y < -SKY_GROUND_THRESHOLD] - ground\r\n\t// if y >= 0 and < 1 [eyeRay.y <= 0 and > -SKY_GROUND_THRESHOLD] - horizon\r\n\t// if y < 0 [eyeRay.y > 0] - sky\r\n\tvec3 col = vec3(0.0, 0.0, 0.0);\r\n\r\n\t#ifdef SUN_HIGH_QUALITY\r\n\t\tvec3 ray = normalize(v_Vertex);\r\n\t\tfloat y = ray.y / SKY_GROUND_THRESHOLD;\r\n\t#elif defined(SUN_SIMPLE) \r\n\t\tvec3 ray = v_RayDir;\r\n\t\tfloat y = ray.y / SKY_GROUND_THRESHOLD;\t\r\n\t#else\r\n\t\tfloat y = v_SkyGroundFactor;\r\n\t#endif\r\n\r\n\t// if we did precalculate color in vprog: just do lerp between them\r\n\tcol = mix(v_SkyColor, v_GroundColor, clamp(y,0.0,1.0));\r\n\r\n\t#if defined(SUN_HIGH_QUALITY)||defined(SUN_SIMPLE)\r\n\t\tif (y < 0.0)\r\n\t\t\tcol += v_SunColor * calcSunAttenuation(-u_SunLight.direction, -ray);\r\n\t#endif\r\n\r\n\tcol = sqrt(col);//linear space convert to gamma space\r\n\tgl_FragColor=vec4(col,1.0);\r\n}\r\n\r\n"; var SkyBoxProceduralVS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#include \"Lighting.glsl\";\r\n\r\n#define OUTER_RADIUS 1.025\r\n#define RAYLEIGH (mix(0.0, 0.0025, pow(u_AtmosphereThickness,2.5)))// Rayleigh constant Rayleigh为夜空光和极光亮度单位\r\n#define MIE 0.0010 // Mie constant 米氏散射\r\n#define SUN_BRIGHTNESS 20.0 // Sun brightness\r\n#define MAX_SCATTER 50.0 // Maximum scattering value, to prevent math overflows on Adrenos\r\n\r\nconst float SKY_GROUND_THRESHOLD = 0.02;\r\nconst float outerRadius = OUTER_RADIUS;\r\nconst float outerRadius2 = OUTER_RADIUS*OUTER_RADIUS;\r\nconst float innerRadius = 1.0;\r\nconst float innerRadius2 = 1.0;\r\nconst float cameraHeight = 0.0001;\r\n\r\nconst float HDSundiskIntensityFactor = 15.0;\r\nconst float simpleSundiskIntensityFactor = 27.0;\r\n\r\nconst float sunScale = 400.0 * SUN_BRIGHTNESS;\r\nconst float kmESun = MIE * SUN_BRIGHTNESS;\r\nconst float km4PI = MIE * 4.0 * 3.14159265;\r\nconst float scale = 1.0 / (OUTER_RADIUS - 1.0);\r\nconst float scaleDepth = 0.25;\r\nconst float scaleOverScaleDepth = (1.0 / (OUTER_RADIUS - 1.0)) / 0.25;\r\nconst float samples = 2.0; // THIS IS UNROLLED MANUALLY, DON'T TOUCH\r\n\r\n// RGB wavelengths .35 (.62=158), .43 (.68=174), .525 (.75=190)\r\nconst vec3 c_DefaultScatteringWavelength = vec3(0.65, 0.57, 0.475);//默认散射波长\r\nconst vec3 c_VariableRangeForScatteringWavelength = vec3(0.15, 0.15, 0.15);//散射播放的可变范围\r\n\r\nattribute vec4 a_Position;\r\n\r\nuniform mat4 u_ViewProjection;\r\nuniform vec3 u_SkyTint;\r\nuniform vec3 u_GroundTint;\r\nuniform float u_Exposure;\r\nuniform float u_AtmosphereThickness;\r\nuniform DirectionLight u_SunLight;\r\n\r\nvarying vec3 v_GroundColor;\r\nvarying vec3 v_SkyColor;\r\n\r\n#ifdef SUN_HIGH_QUALITY\r\n\tvarying vec3 v_Vertex;\r\n#elif defined(SUN_SIMPLE)\r\n\tvarying vec3 v_RayDir;\r\n#else\r\n\tvarying float v_SkyGroundFactor;\r\n#endif\r\n\r\n#if defined(SUN_HIGH_QUALITY)||defined(SUN_SIMPLE)\r\n\tvarying vec3 v_SunColor;\r\n#endif\r\n\r\n// Calculates the Rayleigh phase function\r\nfloat getRayleighPhase(vec3 light, vec3 ray) \r\n{\r\n\tfloat eyeCos = dot(light, ray);\r\n\treturn 0.75 + 0.75*eyeCos*eyeCos;\r\n}\r\n\r\nfloat scaleAngle(float inCos)\r\n{\r\n\tfloat x = 1.0 - inCos;\r\n\treturn 0.25 * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\r\n}\r\n\r\n\r\nvoid main () {\r\n\tgl_Position = u_ViewProjection*a_Position;\r\n\r\n\tvec3 skyTintInGammaSpace = u_SkyTint;//支持非GAMMA空间后要调整\r\n\tvec3 scatteringWavelength = mix(c_DefaultScatteringWavelength-c_VariableRangeForScatteringWavelength,c_DefaultScatteringWavelength+c_VariableRangeForScatteringWavelength,vec3(1.0) - skyTintInGammaSpace); // using Tint in sRGB+ gamma allows for more visually linear interpolation and to keep (0.5) at (128, gray in sRGB) point\r\n\tvec3 invWavelength = 1.0 / pow(scatteringWavelength, vec3(4.0));\r\n\r\n\tfloat krESun = RAYLEIGH * SUN_BRIGHTNESS;\r\n\tfloat kr4PI = RAYLEIGH * 4.0 * 3.14159265;\r\n\r\n\tvec3 cameraPos = vec3(0.0,innerRadius + cameraHeight,0.0); // The camera's current position\r\n\r\n\t// Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)\r\n\tvec3 eyeRay = normalize(a_Position.xyz);\r\n\r\n\tfloat far = 0.0;\r\n\tvec3 cIn, cOut;\r\n\tif (eyeRay.y >= 0.0) {// Sky\r\n\t\t// Calculate the length of the \"atmosphere\"\r\n\t\tfar = sqrt(outerRadius2 + innerRadius2 * eyeRay.y * eyeRay.y - innerRadius2) - innerRadius * eyeRay.y;\r\n\r\n\t\t// Calculate the ray's starting position, then calculate its scattering offset\r\n\t\tfloat height = innerRadius + cameraHeight;\r\n\t\tfloat depth = exp(scaleOverScaleDepth * -cameraHeight);\r\n\t\tfloat startAngle = dot(eyeRay, cameraPos) / height;\r\n\t\tfloat startOffset = depth*scaleAngle(startAngle);\r\n\r\n\t\t// Initialize the scattering loop variables\r\n\t\tfloat sampleLength = far / samples;\r\n\t\tfloat scaledLength = sampleLength * scale;\r\n\t\tvec3 sampleRay = eyeRay * sampleLength;\r\n\t\tvec3 samplePoint = cameraPos + sampleRay * 0.5;\r\n\r\n\t\tvec3 frontColor = vec3(0.0);\r\n\t\t//unrolling this manually to avoid some platform for loop slow\r\n\t\t{\r\n\t\t\tfloat height = length(samplePoint);\r\n\t\t\tfloat depth = exp(scaleOverScaleDepth * (innerRadius - height));\r\n\t\t\tfloat lightAngle = dot(-u_SunLight.direction, samplePoint) / height;\r\n\t\t\tfloat cameraAngle = dot(eyeRay, samplePoint) / height;\r\n\t\t\tfloat scatter = (startOffset + depth*(scaleAngle(lightAngle) - scaleAngle(cameraAngle)));\r\n\t\t\tvec3 attenuate = exp(-clamp(scatter, 0.0, MAX_SCATTER) * (invWavelength * kr4PI + km4PI));\r\n\r\n\t\t\tfrontColor += attenuate * (depth * scaledLength);\r\n\t\t\tsamplePoint += sampleRay;\r\n\t\t}\r\n\t\t{\r\n\t\t\tfloat height = length(samplePoint);\r\n\t\t\tfloat depth = exp(scaleOverScaleDepth * (innerRadius - height));\r\n\t\t\tfloat lightAngle = dot(-u_SunLight.direction, samplePoint) / height;\r\n\t\t\tfloat cameraAngle = dot(eyeRay, samplePoint) / height;\r\n\t\t\tfloat scatter = (startOffset + depth*(scaleAngle(lightAngle) - scaleAngle(cameraAngle)));\r\n\t\t\tvec3 attenuate = exp(-clamp(scatter, 0.0, MAX_SCATTER) * (invWavelength * kr4PI + km4PI));\r\n\r\n\t\t\tfrontColor += attenuate * (depth * scaledLength);\r\n\t\t\tsamplePoint += sampleRay;\r\n\t\t}\r\n\r\n\t\t// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader\r\n\t\tcIn = frontColor * (invWavelength * krESun);\r\n\t\tcOut = frontColor * kmESun;\r\n\t} else {// Ground\r\n\t\tfar = (-cameraHeight) / (min(-0.001, eyeRay.y));\r\n\t\tvec3 pos = cameraPos + far * eyeRay;\r\n\r\n\t\t// Calculate the ray's starting position, then calculate its scattering offset\r\n\t\tfloat depth = exp((-cameraHeight) * (1.0/scaleDepth));\r\n\t\tfloat cameraAngle = dot(-eyeRay, pos);\r\n\t\tfloat lightAngle = dot(-u_SunLight.direction, pos);\r\n\t\tfloat cameraScale = scaleAngle(cameraAngle);\r\n\t\tfloat lightScale = scaleAngle(lightAngle);\r\n\t\tfloat cameraOffset = depth*cameraScale;\r\n\t\tfloat temp = lightScale + cameraScale;\r\n\r\n\t\t// Initialize the scattering loop variables\r\n\t\tfloat sampleLength = far / samples;\r\n\t\tfloat scaledLength = sampleLength * scale;\r\n\t\tvec3 sampleRay = eyeRay * sampleLength;\r\n\t\tvec3 samplePoint = cameraPos + sampleRay * 0.5;\r\n\r\n\t\t// Now loop through the sample rays\r\n\t\tvec3 frontColor = vec3(0.0, 0.0, 0.0);\r\n\t\tvec3 attenuate;\r\n\r\n\t\t// Loop removed because we kept hitting SM2.0 temp variable limits. Doesn't affect the image too much.\r\n\t\t{\r\n\t\t\tfloat height = length(samplePoint);\r\n\t\t\tfloat depth = exp(scaleOverScaleDepth * (innerRadius - height));\r\n\t\t\tfloat scatter = depth*temp - cameraOffset;\r\n\t\t\tattenuate = exp(-clamp(scatter, 0.0, MAX_SCATTER) * (invWavelength * kr4PI + km4PI));\r\n\t\t\tfrontColor += attenuate * (depth * scaledLength);\r\n\t\t\tsamplePoint += sampleRay;\r\n\t\t}\r\n\r\n\t\tcIn = frontColor * (invWavelength * krESun + kmESun);\r\n\t\tcOut = clamp(attenuate, 0.0, 1.0);\r\n\t}\r\n\r\n\t#ifdef SUN_HIGH_QUALITY\r\n\t\tv_Vertex = -a_Position.xyz;\r\n\t#elif defined(SUN_SIMPLE) \r\n\t\tv_RayDir = -eyeRay;\r\n\t#else\r\n\t\tv_SkyGroundFactor = -eyeRay.y / SKY_GROUND_THRESHOLD;\r\n\t#endif\r\n\r\n\t// if we want to calculate color in vprog:\r\n\t// in case of linear: multiply by _Exposure in here (even in case of lerp it will be common multiplier, so we can skip mul in fshader)\r\n\tv_GroundColor = u_Exposure * (cIn + u_GroundTint*u_GroundTint * cOut);//u_GroundColor*u_GroundColor is gamma space convert to linear space\r\n\tv_SkyColor = u_Exposure * (cIn * getRayleighPhase(-u_SunLight.direction, -eyeRay));\r\n\r\n\t\r\n\t// The sun should have a stable intensity in its course in the sky. Moreover it should match the highlight of a purely specular material.\r\n\t// This matching was done using the Unity3D standard shader BRDF1 on the 5/31/2017\r\n\t// Finally we want the sun to be always bright even in LDR thus the normalization of the lightColor for low intensity.\r\n\tfloat lightColorIntensity = clamp(length(u_SunLight.color), 0.25, 1.0);\r\n\r\n\t#ifdef SUN_HIGH_QUALITY \r\n\t\tv_SunColor = HDSundiskIntensityFactor * clamp(cOut,0.0,1.0) * u_SunLight.color / lightColorIntensity;\r\n\t#elif defined(SUN_SIMPLE) \r\n\t\tv_SunColor = simpleSundiskIntensityFactor * clamp(cOut * sunScale,0.0,1.0) * u_SunLight.color / lightColorIntensity;\r\n\t#endif\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}\r\n"; var TrailPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\nuniform sampler2D u_MainTexture;\r\nuniform vec4 u_MainColor;\r\n\r\nvarying vec2 v_Texcoord0;\r\nvarying vec4 v_Color;\r\n\r\nvoid main()\r\n{\r\n\tvec4 color = 2.0 * u_MainColor * v_Color;\r\n\t#ifdef MAINTEXTURE\r\n\t\tvec4 mainTextureColor = texture2D(u_MainTexture, v_Texcoord0);\r\n\t\tcolor *= mainTextureColor;\r\n\t#endif\r\n\tgl_FragColor = color;\r\n}\r\n\r\n "; var TrailVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec3 a_Position;\r\nattribute vec3 a_OffsetVector;\r\nattribute vec4 a_Color;\r\nattribute float a_Texcoord0X;\r\nattribute float a_Texcoord0Y;\r\nattribute float a_BirthTime;\r\n\r\nuniform mat4 u_View;\r\nuniform mat4 u_Projection;\r\n\r\nuniform vec4 u_TilingOffset;\r\n\r\nuniform float u_CurTime;\r\nuniform float u_LifeTime;\r\nuniform vec4 u_WidthCurve[10];\r\nuniform int u_WidthCurveKeyLength;\r\n\r\nvarying vec2 v_Texcoord0;\r\nvarying vec4 v_Color;\r\n\r\nfloat hermiteInterpolate(float t, float outTangent, float inTangent, float duration, float value1, float value2)\r\n{\r\n\tfloat t2 = t * t;\r\n\tfloat t3 = t2 * t;\r\n\tfloat a = 2.0 * t3 - 3.0 * t2 + 1.0;\r\n\tfloat b = t3 - 2.0 * t2 + t;\r\n\tfloat c = t3 - t2;\r\n\tfloat d = -2.0 * t3 + 3.0 * t2;\r\n\treturn a * value1 + b * outTangent * duration + c * inTangent * duration + d * value2;\r\n}\r\n\r\nfloat getCurWidth(in float normalizeTime)\r\n{\r\n\tfloat width;\r\n\tif(normalizeTime == 0.0){\r\n\t\twidth=u_WidthCurve[0].w;\r\n\t}\r\n\telse if(normalizeTime >= 1.0){\r\n\t\twidth=u_WidthCurve[u_WidthCurveKeyLength - 1].w;\r\n\t}\r\n\telse{\r\n\t\tfor(int i = 0; i < 10; i ++ )\r\n\t\t{\r\n\t\t\tif(normalizeTime == u_WidthCurve[i].x){\r\n\t\t\t\twidth=u_WidthCurve[i].w;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvec4 lastFrame = u_WidthCurve[i];\r\n\t\t\tvec4 nextFrame = u_WidthCurve[i + 1];\r\n\t\t\tif(normalizeTime > lastFrame.x && normalizeTime < nextFrame.x)\r\n\t\t\t{\r\n\t\t\t\tfloat duration = nextFrame.x - lastFrame.x;\r\n\t\t\t\tfloat t = (normalizeTime - lastFrame.x) / duration;\r\n\t\t\t\tfloat outTangent = lastFrame.z;\r\n\t\t\t\tfloat inTangent = nextFrame.y;\r\n\t\t\t\tfloat value1 = lastFrame.w;\r\n\t\t\t\tfloat value2 = nextFrame.w;\r\n\t\t\t\twidth=hermiteInterpolate(t, outTangent, inTangent, duration, value1, value2);\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn width;\r\n}\t\r\n\r\nvoid main()\r\n{\r\n\tfloat normalizeTime = (u_CurTime - a_BirthTime) / u_LifeTime;\r\n\t\r\n\t#ifdef TILINGOFFSET\r\n\t\tv_Texcoord0 = vec2(a_Texcoord0X, 1.0 - a_Texcoord0Y) * u_TilingOffset.xy + u_TilingOffset.zw;\r\n\t#else\r\n\t\tv_Texcoord0 = vec2(a_Texcoord0X, a_Texcoord0Y);\r\n\t#endif\r\n\t\r\n\tv_Color = a_Color;\r\n\t\r\n\tgl_Position = u_Projection * u_View * vec4(a_Position + a_OffsetVector * getCurWidth(normalizeTime),1.0);\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}\r\n"; var UnlitPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#if defined(COLOR)&&defined(ENABLEVERTEXCOLOR)\r\n\tvarying vec4 v_Color;\r\n#endif\r\n\r\n#ifdef ALBEDOTEXTURE\r\n\tuniform sampler2D u_AlbedoTexture;\r\n\tvarying vec2 v_Texcoord0;\r\n#endif\r\n\r\nuniform vec4 u_AlbedoColor;\r\n\r\n#ifdef ALPHATEST\r\n\tuniform float u_AlphaTestValue;\r\n#endif\r\n\r\n#ifdef FOG\r\n\tuniform float u_FogStart;\r\n\tuniform float u_FogRange;\r\n\t#ifdef ADDTIVEFOG\r\n\t#else\r\n\t\tuniform vec3 u_FogColor;\r\n\t#endif\r\n#endif\r\n\r\nvoid main()\r\n{\r\n\tvec4 color = u_AlbedoColor;\r\n\t#ifdef ALBEDOTEXTURE\r\n\t\tcolor *= texture2D(u_AlbedoTexture, v_Texcoord0);\r\n\t#endif\r\n\t#if defined(COLOR)&&defined(ENABLEVERTEXCOLOR)\r\n\t\tcolor *= v_Color;\r\n\t#endif\r\n\t\r\n\t#ifdef ALPHATEST\r\n\t\tif(color.a < u_AlphaTestValue)\r\n\t\t\tdiscard;\r\n\t#endif\r\n\t\r\n\tgl_FragColor = color;\r\n\t\r\n\t#ifdef FOG\r\n\t\tfloat lerpFact = clamp((1.0 / gl_FragCoord.w - u_FogStart) / u_FogRange, 0.0, 1.0);\r\n\t\t#ifdef ADDTIVEFOG\r\n\t\t\tgl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.0), lerpFact);\r\n\t\t#else\r\n\t\t\tgl_FragColor.rgb = mix(gl_FragColor.rgb, u_FogColor, lerpFact);\r\n\t\t#endif\r\n\t#endif\r\n\t\r\n}\r\n\r\n"; var UnlitVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_Position;\r\n\r\nattribute vec2 a_Texcoord0;\r\n\r\n#ifdef GPU_INSTANCE\r\n\tattribute mat4 a_MvpMatrix;\r\n#else\r\n\tuniform mat4 u_MvpMatrix;\r\n#endif\r\n\r\nattribute vec4 a_Color;\r\nvarying vec4 v_Color;\r\nvarying vec2 v_Texcoord0;\r\n\r\n#ifdef TILINGOFFSET\r\n\tuniform vec4 u_TilingOffset;\r\n#endif\r\n\r\n#ifdef BONE\r\n\tconst int c_MaxBoneCount = 24;\r\n\tattribute vec4 a_BoneIndices;\r\n\tattribute vec4 a_BoneWeights;\r\n\tuniform mat4 u_Bones[c_MaxBoneCount];\r\n#endif\r\n\r\nvoid main() {\r\n\tvec4 position;\r\n\t#ifdef BONE\r\n\t\tmat4 skinTransform = u_Bones[int(a_BoneIndices.x)] * a_BoneWeights.x;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.y)] * a_BoneWeights.y;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.z)] * a_BoneWeights.z;\r\n\t\tskinTransform += u_Bones[int(a_BoneIndices.w)] * a_BoneWeights.w;\r\n\t\tposition=skinTransform*a_Position;\r\n\t#else\r\n\t\tposition=a_Position;\r\n\t#endif\r\n\t#ifdef GPU_INSTANCE\r\n\t\tgl_Position = a_MvpMatrix * position;\r\n\t#else\r\n\t\tgl_Position = u_MvpMatrix * position;\r\n\t#endif\r\n\r\n\t#ifdef TILINGOFFSET\r\n\t\tv_Texcoord0=TransformUV(a_Texcoord0,u_TilingOffset);\r\n\t#else\r\n\t\tv_Texcoord0=a_Texcoord0;\r\n\t#endif\r\n\r\n\t#if defined(COLOR)&&defined(ENABLEVERTEXCOLOR)\r\n\t\tv_Color = a_Color;\r\n\t#endif\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}"; var WaterPrimaryPS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#ifdef MAINTEXTURE\r\n\tuniform sampler2D u_MainTexture;\r\n#endif\r\n\r\n#ifdef NORMALTEXTURE\r\n\tuniform sampler2D u_NormalTexture;\r\n#endif\r\n\r\nuniform vec4 u_HorizonColor;\r\n\r\nvarying vec3 v_Normal;\r\nvarying vec3 v_Tangent;\r\nvarying vec3 v_Binormal;\r\nvarying vec3 v_ViewDir;\r\nvarying vec2 v_Texcoord0;\r\nvarying vec2 v_Texcoord1;\r\n\r\n\r\n#include \"Lighting.glsl\"\r\n\r\n\r\n\r\nvec3 NormalSampleToWorldSpace(vec4 normalMapSample) {\r\n\tvec3 normalT;\r\n\tnormalT.x = 2.0 * normalMapSample.x - 1.0;\r\n\tnormalT.y = 1.0 - 2.0 * normalMapSample.y;\r\n\tnormalT.z = sqrt(1.0 - clamp(dot(normalT.xy, normalT.xy), 0.0, 1.0));\r\n\r\n\tvec3 bumpedNormal = normalize(normalT);\r\n\r\n\treturn bumpedNormal;\r\n}\r\n\r\n\r\nvoid main()\r\n{\r\n\tvec4 bumpColor1 = texture2D(u_NormalTexture, v_Texcoord0);\r\n\tvec4 bumpColor2 = texture2D(u_NormalTexture, v_Texcoord1);\r\n\r\n\tvec3 normal1 = NormalSampleToWorldSpace(bumpColor1);\r\n\tvec3 normal2 = NormalSampleToWorldSpace(bumpColor2);\r\n\t\r\n\tvec3 normal = normalize((normal1 + normal2) * 0.5);\r\n\tvec3 viewDir = normalize(v_ViewDir);\r\n\tfloat fresnel = dot(viewDir, normal);\r\n\t\r\n\tvec4 waterColor = texture2D(u_MainTexture, vec2(fresnel, fresnel));\r\n\t\r\n\tvec4 color;\r\n\tcolor.rgb = mix(waterColor.rgb, u_HorizonColor.rgb, vec3(waterColor.a));\r\n\tcolor.a = u_HorizonColor.a;\r\n\t\r\n\tgl_FragColor = color;\r\n}\r\n\r\n\r\n"; var WaterPrimaryVS = "#include \"Lighting.glsl\";\r\n\r\nattribute vec4 a_Position;\r\nattribute vec3 a_Normal;\r\nattribute vec4 a_Tangent0;\r\n\r\nuniform mat4 u_MvpMatrix;\r\nuniform mat4 u_WorldMat;\r\nuniform vec3 u_CameraPos;\r\nuniform float u_WaveScale;\r\nuniform vec4 u_WaveSpeed;\r\nuniform float u_Time;\r\n\r\nvarying vec3 v_Normal;\r\nvarying vec3 v_Tangent;\r\nvarying vec3 v_Binormal;\r\nvarying vec3 v_ViewDir;\r\nvarying vec2 v_Texcoord0;\r\nvarying vec2 v_Texcoord1;\r\n\r\nvoid main()\r\n{\r\n\tvec4 positionWorld = u_WorldMat * a_Position;\r\n\tvec4 position = u_MvpMatrix * a_Position;\r\n\t\r\n\tvec4 temp = vec4(positionWorld.x, positionWorld.z, positionWorld.x, positionWorld.z) * u_WaveScale + u_WaveSpeed * u_WaveScale * u_Time;\r\n\t\r\n\tv_Texcoord0 = temp.xy * vec2(0.4, 0.45);\r\n\tv_Texcoord1 = temp.wz;\r\n\t\r\n\tmat3 worldMat = mat3(u_WorldMat);\r\n\tv_Normal = worldMat * a_Normal;\r\n\tv_Tangent = worldMat * a_Tangent0.xyz;\r\n\tv_Binormal = cross(v_Normal, v_Tangent) * a_Tangent0.w;\r\n\t\r\n\tv_ViewDir = u_CameraPos - positionWorld.xyz;\r\n\tgl_Position = position;\r\n\tgl_Position=remapGLPositionZ(gl_Position);\r\n}"; class ShaderInit3D { constructor() { } static __init__() { Shader3D.SHADERDEFINE_LEGACYSINGALLIGHTING = Shader3D.getDefineByName("LEGACYSINGLELIGHTING"); Shader3D.SHADERDEFINE_GRAPHICS_API_GLES2 = Shader3D.getDefineByName("GRAPHICS_API_GLES2"); Shader3D.SHADERDEFINE_GRAPHICS_API_GLES3 = Shader3D.getDefineByName("GRAPHICS_API_GLES3"); Shader3D.addInclude("Lighting.glsl", LightingGLSL); Shader3D.addInclude("ShadowSampleTent.glsl", ShadowSampleTentGLSL); Shader3D.addInclude("GlobalIllumination.glsl", GlobalIllumination); Shader3D.addInclude("Shadow.glsl", ShadowGLSL); Shader3D.addInclude("ShadowCasterVS.glsl", ShadowCasterVSGLSL); Shader3D.addInclude("ShadowCasterFS.glsl", ShadowCasterFSGLSL); Shader3D.addInclude("Colors.glsl", ColorsGLSL); Shader3D.addInclude("Sampling.glsl", SamplingGLSL); Shader3D.addInclude("StdLib.glsl", StdLibGLSL); Shader3D.addInclude("PBRVSInput.glsl", PBRVSInput); Shader3D.addInclude("PBRFSInput.glsl", PBRFSInput); Shader3D.addInclude("LayaPBRBRDF.glsl", LayaPBRBRDF); Shader3D.addInclude("PBRCore.glsl", PBRCore); Shader3D.addInclude("PBRVertex.glsl", PBRVertex); var attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0, 'a_Color': VertexMesh.MESH_COLOR0, 'a_Normal': VertexMesh.MESH_NORMAL0, 'a_Texcoord0': VertexMesh.MESH_TEXTURECOORDINATE0, 'a_Texcoord1': VertexMesh.MESH_TEXTURECOORDINATE1, 'a_BoneWeights': VertexMesh.MESH_BLENDWEIGHT0, 'a_BoneIndices': VertexMesh.MESH_BLENDINDICES0, 'a_Tangent0': VertexMesh.MESH_TANGENT0, 'a_MvpMatrix': VertexMesh.MESH_MVPMATRIX_ROW0, 'a_WorldMat': VertexMesh.MESH_WORLDMATRIX_ROW0 }; var uniformMap = { 'u_Bones': Shader3D.PERIOD_CUSTOM, 'u_DiffuseTexture': Shader3D.PERIOD_MATERIAL, 'u_SpecularTexture': Shader3D.PERIOD_MATERIAL, 'u_NormalTexture': Shader3D.PERIOD_MATERIAL, 'u_AlphaTestValue': Shader3D.PERIOD_MATERIAL, 'u_DiffuseColor': Shader3D.PERIOD_MATERIAL, 'u_MaterialSpecular': Shader3D.PERIOD_MATERIAL, 'u_Shininess': Shader3D.PERIOD_MATERIAL, 'u_TilingOffset': Shader3D.PERIOD_MATERIAL, 'u_WorldMat': Shader3D.PERIOD_SPRITE, 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_LightmapScaleOffset': Shader3D.PERIOD_SPRITE, 'u_LightMap': Shader3D.PERIOD_SPRITE, 'u_LightMapDirection': Shader3D.PERIOD_SPRITE, 'u_CameraPos': Shader3D.PERIOD_CAMERA, 'u_Viewport': Shader3D.PERIOD_CAMERA, 'u_ProjectionParams': Shader3D.PERIOD_CAMERA, 'u_View': Shader3D.PERIOD_CAMERA, 'u_ViewProjection': Shader3D.PERIOD_CAMERA, 'u_ReflectTexture': Shader3D.PERIOD_SCENE, 'u_ReflectIntensity': Shader3D.PERIOD_SCENE, 'u_FogStart': Shader3D.PERIOD_SCENE, 'u_FogRange': Shader3D.PERIOD_SCENE, 'u_FogColor': Shader3D.PERIOD_SCENE, 'u_DirationLightCount': Shader3D.PERIOD_SCENE, 'u_LightBuffer': Shader3D.PERIOD_SCENE, 'u_LightClusterBuffer': Shader3D.PERIOD_SCENE, 'u_AmbientColor': Shader3D.PERIOD_SCENE, 'u_ShadowBias': Shader3D.PERIOD_SCENE, 'u_ShadowLightDirection': Shader3D.PERIOD_SCENE, 'u_ShadowMap': Shader3D.PERIOD_SCENE, 'u_ShadowParams': Shader3D.PERIOD_SCENE, 'u_ShadowSplitSpheres': Shader3D.PERIOD_SCENE, 'u_ShadowMatrices': Shader3D.PERIOD_SCENE, 'u_ShadowMapSize': Shader3D.PERIOD_SCENE, 'u_SpotShadowMap': Shader3D.PERIOD_SCENE, 'u_SpotViewProjectMatrix': Shader3D.PERIOD_SCENE, 'u_ShadowLightPosition': Shader3D.PERIOD_SCENE, 'u_AmbientSHAr': Shader3D.PERIOD_SCENE, 'u_AmbientSHAg': Shader3D.PERIOD_SCENE, 'u_AmbientSHAb': Shader3D.PERIOD_SCENE, 'u_AmbientSHBr': Shader3D.PERIOD_SCENE, 'u_AmbientSHBg': Shader3D.PERIOD_SCENE, 'u_AmbientSHBb': Shader3D.PERIOD_SCENE, 'u_AmbientSHC': Shader3D.PERIOD_SCENE, 'u_DirectionLight.color': Shader3D.PERIOD_SCENE, 'u_DirectionLight.direction': Shader3D.PERIOD_SCENE, 'u_PointLight.position': Shader3D.PERIOD_SCENE, 'u_PointLight.range': Shader3D.PERIOD_SCENE, 'u_PointLight.color': Shader3D.PERIOD_SCENE, 'u_SpotLight.position': Shader3D.PERIOD_SCENE, 'u_SpotLight.direction': Shader3D.PERIOD_SCENE, 'u_SpotLight.range': Shader3D.PERIOD_SCENE, 'u_SpotLight.spot': Shader3D.PERIOD_SCENE, 'u_SpotLight.color': Shader3D.PERIOD_SCENE }; var stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; var shader = Shader3D.add("BLINNPHONG", null, null, true); var subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(MeshBlinnPhongVS, MeshBlinnPhongPS, stateMap, "Forward"); var shaderPass = subShader.addShaderPass(MeshBlinnPhongShadowCasterVS, MeshBlinnPhongShadowCasterPS, stateMap, "ShadowCaster"); attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0, 'a_Color': VertexMesh.MESH_COLOR0 }; uniformMap = { 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_Color': Shader3D.PERIOD_MATERIAL }; stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; shader = Shader3D.add("LineShader"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(lineVS, linePS, stateMap); attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0, 'a_Color': VertexMesh.MESH_COLOR0, 'a_Texcoord0': VertexMesh.MESH_TEXTURECOORDINATE0, 'a_BoneWeights': VertexMesh.MESH_BLENDWEIGHT0, 'a_BoneIndices': VertexMesh.MESH_BLENDINDICES0, 'a_MvpMatrix': VertexMesh.MESH_MVPMATRIX_ROW0 }; uniformMap = { 'u_Bones': Shader3D.PERIOD_CUSTOM, 'u_AlbedoTexture': Shader3D.PERIOD_MATERIAL, 'u_AlbedoColor': Shader3D.PERIOD_MATERIAL, 'u_TilingOffset': Shader3D.PERIOD_MATERIAL, 'u_AlphaTestValue': Shader3D.PERIOD_MATERIAL, 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_FogStart': Shader3D.PERIOD_SCENE, 'u_FogRange': Shader3D.PERIOD_SCENE, 'u_FogColor': Shader3D.PERIOD_SCENE }; stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; shader = Shader3D.add("Unlit", null, null, true); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(UnlitVS, UnlitPS, stateMap); attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0, 'a_Texcoord0': VertexMesh.MESH_TEXTURECOORDINATE0, 'a_BoneWeights': VertexMesh.MESH_BLENDWEIGHT0, 'a_BoneIndices': VertexMesh.MESH_BLENDINDICES0, 'a_MvpMatrix': VertexMesh.MESH_MVPMATRIX_ROW0 }; uniformMap = { 'u_Bones': Shader3D.PERIOD_CUSTOM, 'u_AlbedoTexture': Shader3D.PERIOD_MATERIAL, 'u_AlbedoColor': Shader3D.PERIOD_MATERIAL, 'u_TilingOffset': Shader3D.PERIOD_MATERIAL, 'u_AlphaTestValue': Shader3D.PERIOD_MATERIAL, 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_FogStart': Shader3D.PERIOD_SCENE, 'u_FogRange': Shader3D.PERIOD_SCENE, 'u_FogColor': Shader3D.PERIOD_SCENE }; stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; shader = Shader3D.add("Effect", null, null, true); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(EffectVS, EffectPS, stateMap); attributeMap = { 'a_CornerTextureCoordinate': VertexShuriKenParticle.PARTICLE_CORNERTEXTURECOORDINATE0, 'a_MeshPosition': VertexShuriKenParticle.PARTICLE_POSITION0, 'a_MeshColor': VertexShuriKenParticle.PARTICLE_COLOR0, 'a_MeshTextureCoordinate': VertexShuriKenParticle.PARTICLE_TEXTURECOORDINATE0, 'a_ShapePositionStartLifeTime': VertexShuriKenParticle.PARTICLE_SHAPEPOSITIONSTARTLIFETIME, 'a_DirectionTime': VertexShuriKenParticle.PARTICLE_DIRECTIONTIME, 'a_StartColor': VertexShuriKenParticle.PARTICLE_STARTCOLOR0, 'a_EndColor': VertexShuriKenParticle.PARTICLE_ENDCOLOR0, 'a_StartSize': VertexShuriKenParticle.PARTICLE_STARTSIZE, 'a_StartRotation0': VertexShuriKenParticle.PARTICLE_STARTROTATION, 'a_StartSpeed': VertexShuriKenParticle.PARTICLE_STARTSPEED, 'a_Random0': VertexShuriKenParticle.PARTICLE_RANDOM0, 'a_Random1': VertexShuriKenParticle.PARTICLE_RANDOM1, 'a_SimulationWorldPostion': VertexShuriKenParticle.PARTICLE_SIMULATIONWORLDPOSTION, 'a_SimulationWorldRotation': VertexShuriKenParticle.PARTICLE_SIMULATIONWORLDROTATION }; uniformMap = { 'u_Tintcolor': Shader3D.PERIOD_MATERIAL, 'u_TilingOffset': Shader3D.PERIOD_MATERIAL, 'u_texture': Shader3D.PERIOD_MATERIAL, 'u_WorldPosition': Shader3D.PERIOD_SPRITE, 'u_WorldRotation': Shader3D.PERIOD_SPRITE, 'u_PositionScale': Shader3D.PERIOD_SPRITE, 'u_SizeScale': Shader3D.PERIOD_SPRITE, 'u_ScalingMode': Shader3D.PERIOD_SPRITE, 'u_Gravity': Shader3D.PERIOD_SPRITE, 'u_ThreeDStartRotation': Shader3D.PERIOD_SPRITE, 'u_StretchedBillboardLengthScale': Shader3D.PERIOD_SPRITE, 'u_StretchedBillboardSpeedScale': Shader3D.PERIOD_SPRITE, 'u_SimulationSpace': Shader3D.PERIOD_SPRITE, 'u_CurrentTime': Shader3D.PERIOD_SPRITE, 'u_ColorOverLifeGradientAlphas': Shader3D.PERIOD_SPRITE, 'u_ColorOverLifeGradientColors': Shader3D.PERIOD_SPRITE, 'u_MaxColorOverLifeGradientAlphas': Shader3D.PERIOD_SPRITE, 'u_MaxColorOverLifeGradientColors': Shader3D.PERIOD_SPRITE, 'u_VOLVelocityConst': Shader3D.PERIOD_SPRITE, 'u_VOLVelocityGradientX': Shader3D.PERIOD_SPRITE, 'u_VOLVelocityGradientY': Shader3D.PERIOD_SPRITE, 'u_VOLVelocityGradientZ': Shader3D.PERIOD_SPRITE, 'u_VOLVelocityConstMax': Shader3D.PERIOD_SPRITE, 'u_VOLVelocityGradientMaxX': Shader3D.PERIOD_SPRITE, 'u_VOLVelocityGradientMaxY': Shader3D.PERIOD_SPRITE, 'u_VOLVelocityGradientMaxZ': Shader3D.PERIOD_SPRITE, 'u_VOLSpaceType': Shader3D.PERIOD_SPRITE, 'u_SOLSizeGradient': Shader3D.PERIOD_SPRITE, 'u_SOLSizeGradientX': Shader3D.PERIOD_SPRITE, 'u_SOLSizeGradientY': Shader3D.PERIOD_SPRITE, 'u_SOLSizeGradientZ': Shader3D.PERIOD_SPRITE, 'u_SOLSizeGradientMax': Shader3D.PERIOD_SPRITE, 'u_SOLSizeGradientMaxX': Shader3D.PERIOD_SPRITE, 'u_SOLSizeGradientMaxY': Shader3D.PERIOD_SPRITE, 'u_SOLSizeGradientMaxZ': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityConst': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityConstSeprarate': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradient': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradientX': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradientY': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradientZ': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityConstMax': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityConstMaxSeprarate': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradientMax': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradientMaxX': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradientMaxY': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradientMaxZ': Shader3D.PERIOD_SPRITE, 'u_ROLAngularVelocityGradientMaxW': Shader3D.PERIOD_SPRITE, 'u_TSACycles': Shader3D.PERIOD_SPRITE, 'u_TSASubUVLength': Shader3D.PERIOD_SPRITE, 'u_TSAGradientUVs': Shader3D.PERIOD_SPRITE, 'u_TSAMaxGradientUVs': Shader3D.PERIOD_SPRITE, 'u_CameraPos': Shader3D.PERIOD_CAMERA, 'u_CameraDirection': Shader3D.PERIOD_CAMERA, 'u_CameraUp': Shader3D.PERIOD_CAMERA, 'u_View': Shader3D.PERIOD_CAMERA, 'u_Projection': Shader3D.PERIOD_CAMERA, 'u_FogStart': Shader3D.PERIOD_SCENE, 'u_FogRange': Shader3D.PERIOD_SCENE, 'u_FogColor': Shader3D.PERIOD_SCENE }; stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; shader = Shader3D.add("PARTICLESHURIKEN"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(ParticleShuriKenVS, ParticleShuriKenPS, stateMap); attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0 }; uniformMap = { 'u_TintColor': Shader3D.PERIOD_MATERIAL, 'u_Exposure': Shader3D.PERIOD_MATERIAL, 'u_Rotation': Shader3D.PERIOD_MATERIAL, 'u_CubeTexture': Shader3D.PERIOD_MATERIAL, 'u_ViewProjection': Shader3D.PERIOD_CAMERA }; shader = Shader3D.add("SkyBox"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(SkyBoxVS, SkyBoxPS); attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0 }; uniformMap = { 'u_SunSize': Shader3D.PERIOD_MATERIAL, 'u_SunSizeConvergence': Shader3D.PERIOD_MATERIAL, 'u_AtmosphereThickness': Shader3D.PERIOD_MATERIAL, 'u_SkyTint': Shader3D.PERIOD_MATERIAL, 'u_GroundTint': Shader3D.PERIOD_MATERIAL, 'u_Exposure': Shader3D.PERIOD_MATERIAL, 'u_ViewProjection': Shader3D.PERIOD_CAMERA, 'u_SunLight.direction': Shader3D.PERIOD_SCENE, 'u_SunLight.color': Shader3D.PERIOD_SCENE, }; shader = Shader3D.add("SkyBoxProcedural"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(SkyBoxProceduralVS, SkyBoxProceduralPS); attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0, 'a_Normal': VertexMesh.MESH_NORMAL0, 'a_Texcoord0': VertexMesh.MESH_TEXTURECOORDINATE0 }; uniformMap = { 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_WorldMat': Shader3D.PERIOD_SPRITE, 'u_CameraPos': Shader3D.PERIOD_CAMERA, 'u_Viewport': Shader3D.PERIOD_CAMERA, 'u_ProjectionParams': Shader3D.PERIOD_CAMERA, 'u_View': Shader3D.PERIOD_CAMERA, 'u_LightmapScaleOffset': Shader3D.PERIOD_SPRITE, 'u_LightMap': Shader3D.PERIOD_SPRITE, 'u_SplatAlphaTexture': Shader3D.PERIOD_MATERIAL, 'u_DiffuseTexture1': Shader3D.PERIOD_MATERIAL, 'u_DiffuseTexture2': Shader3D.PERIOD_MATERIAL, 'u_DiffuseTexture3': Shader3D.PERIOD_MATERIAL, 'u_DiffuseTexture4': Shader3D.PERIOD_MATERIAL, 'u_DiffuseTexture5': Shader3D.PERIOD_MATERIAL, 'u_DiffuseScaleOffset1': Shader3D.PERIOD_MATERIAL, 'u_DiffuseScaleOffset2': Shader3D.PERIOD_MATERIAL, 'u_DiffuseScaleOffset3': Shader3D.PERIOD_MATERIAL, 'u_DiffuseScaleOffset4': Shader3D.PERIOD_MATERIAL, 'u_DiffuseScaleOffset5': Shader3D.PERIOD_MATERIAL, 'u_FogStart': Shader3D.PERIOD_SCENE, 'u_FogRange': Shader3D.PERIOD_SCENE, 'u_FogColor': Shader3D.PERIOD_SCENE, 'u_DirationLightCount': Shader3D.PERIOD_SCENE, 'u_LightBuffer': Shader3D.PERIOD_SCENE, 'u_LightClusterBuffer': Shader3D.PERIOD_SCENE, 'u_AmbientColor': Shader3D.PERIOD_SCENE, 'u_ShadowMap': Shader3D.PERIOD_SCENE, 'u_shadowMap2': Shader3D.PERIOD_SCENE, 'u_shadowMap3': Shader3D.PERIOD_SCENE, 'u_ShadowSplitSpheres': Shader3D.PERIOD_SCENE, 'u_ShadowMatrices': Shader3D.PERIOD_SCENE, 'u_ShadowMapSize': Shader3D.PERIOD_SCENE, 'u_DirectionLight.color': Shader3D.PERIOD_SCENE, 'u_DirectionLight.direction': Shader3D.PERIOD_SCENE, 'u_PointLight.position': Shader3D.PERIOD_SCENE, 'u_PointLight.range': Shader3D.PERIOD_SCENE, 'u_PointLight.color': Shader3D.PERIOD_SCENE, 'u_SpotLight.position': Shader3D.PERIOD_SCENE, 'u_SpotLight.direction': Shader3D.PERIOD_SCENE, 'u_SpotLight.range': Shader3D.PERIOD_SCENE, 'u_SpotLight.spot': Shader3D.PERIOD_SCENE, 'u_SpotLight.color': Shader3D.PERIOD_SCENE }; stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; shader = Shader3D.add("ExtendTerrain"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(extendTerrainVS, extendTerrainPS, stateMap); attributeMap = { 'a_Position': VertexTrail.TRAIL_POSITION0, 'a_OffsetVector': VertexTrail.TRAIL_OFFSETVECTOR, 'a_Texcoord0X': VertexTrail.TRAIL_TEXTURECOORDINATE0X, 'a_Texcoord0Y': VertexTrail.TRAIL_TEXTURECOORDINATE0Y, 'a_BirthTime': VertexTrail.TRAIL_TIME0, 'a_Color': VertexTrail.TRAIL_COLOR }; uniformMap = { 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_View': Shader3D.PERIOD_CAMERA, 'u_Projection': Shader3D.PERIOD_CAMERA, 'u_TilingOffset': Shader3D.PERIOD_MATERIAL, 'u_MainTexture': Shader3D.PERIOD_MATERIAL, 'u_MainColor': Shader3D.PERIOD_MATERIAL, 'u_CurTime': Shader3D.PERIOD_SPRITE, 'u_LifeTime': Shader3D.PERIOD_SPRITE, 'u_WidthCurve': Shader3D.PERIOD_SPRITE, 'u_WidthCurveKeyLength': Shader3D.PERIOD_SPRITE, 'u_GradientColorkey': Shader3D.PERIOD_SPRITE, 'u_GradientAlphakey': Shader3D.PERIOD_SPRITE }; stateMap = { 's_Cull': Shader3D.RENDER_STATE_CULL, 's_Blend': Shader3D.RENDER_STATE_BLEND, 's_BlendSrc': Shader3D.RENDER_STATE_BLEND_SRC, 's_BlendDst': Shader3D.RENDER_STATE_BLEND_DST, 's_DepthTest': Shader3D.RENDER_STATE_DEPTH_TEST, 's_DepthWrite': Shader3D.RENDER_STATE_DEPTH_WRITE }; shader = Shader3D.add("Trail"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(TrailVS, TrailPS, stateMap); attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0, 'a_Normal': VertexMesh.MESH_NORMAL0, 'a_Tangent0': VertexMesh.MESH_TANGENT0 }; uniformMap = { 'u_MvpMatrix': Shader3D.PERIOD_SPRITE, 'u_WorldMat': Shader3D.PERIOD_SPRITE, 'u_CameraPos': Shader3D.PERIOD_CAMERA, 'u_Time': Shader3D.PERIOD_SCENE, 'u_MainTexture': Shader3D.PERIOD_MATERIAL, 'u_NormalTexture': Shader3D.PERIOD_MATERIAL, 'u_HorizonColor': Shader3D.PERIOD_MATERIAL, 'u_WaveScale': Shader3D.PERIOD_MATERIAL, 'u_WaveSpeed': Shader3D.PERIOD_MATERIAL }; shader = Shader3D.add("WaterPrimary"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(WaterPrimaryVS, WaterPrimaryPS); attributeMap = { 'a_PositionTexcoord': VertexMesh.MESH_POSITION0 }; uniformMap = { 'u_MainTex': Shader3D.PERIOD_MATERIAL, 'u_OffsetScale': Shader3D.PERIOD_MATERIAL }; shader = Shader3D.add("BlitScreen"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); var shaderPass = subShader.addShaderPass(BlitScreenVS, BlitScreenPS); var renderState = shaderPass.renderState; renderState.depthTest = RenderState.DEPTHTEST_ALWAYS; renderState.depthWrite = false; renderState.cull = RenderState.CULL_NONE; renderState.blend = RenderState.BLEND_DISABLE; attributeMap = { 'a_PositionTexcoord': VertexMesh.MESH_POSITION0 }; uniformMap = { 'u_MainTex': Shader3D.PERIOD_MATERIAL, 'u_BloomTex': Shader3D.PERIOD_MATERIAL, 'u_AutoExposureTex': Shader3D.PERIOD_MATERIAL, 'u_MainTex_TexelSize': Shader3D.PERIOD_MATERIAL, 'u_SampleScale': Shader3D.PERIOD_MATERIAL, 'u_Threshold': Shader3D.PERIOD_MATERIAL, 'u_Params': Shader3D.PERIOD_MATERIAL }; shader = Shader3D.add("PostProcessBloom"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); shaderPass = subShader.addShaderPass(BloomVS, BloomPrefilter13PS); renderState = shaderPass.renderState; renderState.depthTest = RenderState.DEPTHTEST_ALWAYS; renderState.depthWrite = false; renderState.cull = RenderState.CULL_NONE; renderState.blend = RenderState.BLEND_DISABLE; subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); shaderPass = subShader.addShaderPass(BloomVS, BloomPrefilter4PS); renderState = shaderPass.renderState; renderState.depthTest = RenderState.DEPTHTEST_ALWAYS; renderState.depthWrite = false; renderState.cull = RenderState.CULL_NONE; renderState.blend = RenderState.BLEND_DISABLE; subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); shaderPass = subShader.addShaderPass(BloomVS, BloomDownsample13PS); renderState = shaderPass.renderState; renderState.depthTest = RenderState.DEPTHTEST_ALWAYS; renderState.depthWrite = false; renderState.cull = RenderState.CULL_NONE; renderState.blend = RenderState.BLEND_DISABLE; subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); shaderPass = subShader.addShaderPass(BloomVS, BloomDownsample4PS); renderState = shaderPass.renderState; renderState.depthTest = RenderState.DEPTHTEST_ALWAYS; renderState.depthWrite = false; renderState.cull = RenderState.CULL_NONE; renderState.blend = RenderState.BLEND_DISABLE; subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); shaderPass = subShader.addShaderPass(BloomVS, BloomUpsampleTentPS); renderState = shaderPass.renderState; renderState.depthTest = RenderState.DEPTHTEST_ALWAYS; renderState.depthWrite = false; renderState.cull = RenderState.CULL_NONE; renderState.blend = RenderState.BLEND_DISABLE; subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); shaderPass = subShader.addShaderPass(BloomVS, BloomUpsampleBoxPS); renderState = shaderPass.renderState; renderState.depthTest = RenderState.DEPTHTEST_ALWAYS; renderState.depthWrite = false; renderState.cull = RenderState.CULL_NONE; renderState.blend = RenderState.BLEND_DISABLE; attributeMap = { 'a_PositionTexcoord': VertexMesh.MESH_POSITION0 }; uniformMap = { 'u_MainTex': Shader3D.PERIOD_MATERIAL, 'u_BloomTex': Shader3D.PERIOD_MATERIAL, 'u_AutoExposureTex': Shader3D.PERIOD_MATERIAL, 'u_Bloom_DirtTileOffset': Shader3D.PERIOD_MATERIAL, 'u_Bloom_DirtTex': Shader3D.PERIOD_MATERIAL, 'u_BloomTex_TexelSize': Shader3D.PERIOD_MATERIAL, 'u_Bloom_Settings': Shader3D.PERIOD_MATERIAL, 'u_Bloom_Color': Shader3D.PERIOD_MATERIAL }; shader = Shader3D.add("PostProcessComposite"); subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); shaderPass = subShader.addShaderPass(CompositeVS, CompositePS); renderState = shaderPass.renderState; renderState.depthTest = RenderState.DEPTHTEST_ALWAYS; renderState.depthWrite = false; renderState.cull = RenderState.CULL_NONE; renderState.blend = RenderState.BLEND_DISABLE; } } class DirectionLight extends LightSprite { constructor() { super(); this._direction = new Vector3(); this._shadowCascadesMode = exports.ShadowCascadesMode.NoCascades; this._shadowTwoCascadeSplits = 1.0 / 3.0; this._shadowFourCascadeSplits = new Vector3(1.0 / 15, 3.0 / 15.0, 7.0 / 15.0); this._lightType = exports.LightType.Directional; } get shadowCascadesMode() { return this._shadowCascadesMode; } set shadowCascadesMode(value) { this._shadowCascadesMode = value; } get shadowTwoCascadeSplits() { return this._shadowTwoCascadeSplits; } set shadowTwoCascadeSplits(value) { this._shadowTwoCascadeSplits = value; } get shadowFourCascadeSplits() { return this._shadowFourCascadeSplits; } set shadowFourCascadeSplits(value) { if (value.x > value.y || value.y > value.z || value.z > 1.0) throw "DiretionLight:Invalid value."; value.cloneTo(this._shadowFourCascadeSplits); } _addToLightQueue() { this._scene._directionLights.add(this); } _removeFromLightQueue() { this._scene._directionLights.remove(this); } } class PointLight extends LightSprite { constructor() { super(); this._range = 6.0; this._lightType = exports.LightType.Point; } get range() { return this._range; } set range(value) { this._range = value; } _addToLightQueue() { this._scene._pointLights.add(this); } _removeFromLightQueue() { this._scene._pointLights.remove(this); } _parse(data, spriteMap) { super._parse(data, spriteMap); this.range = data.range; } } class SpotLight extends LightSprite { constructor() { super(); this._spotAngle = 30.0; this._range = 10.0; this._direction = new Vector3(); this._lightType = exports.LightType.Spot; } get spotAngle() { return this._spotAngle; } set spotAngle(value) { this._spotAngle = Math.max(Math.min(value, 179), 0); } get range() { return this._range; } set range(value) { this._range = value; } _addToLightQueue() { this._scene._spotLights.add(this); } _removeFromLightQueue() { this._scene._spotLights.remove(this); } _parse(data, spriteMap) { super._parse(data, spriteMap); this.range = data.range; this.spotAngle = data.spotAngle; } } class Scene3DUtils { static _createSprite3DInstance(nodeData, spriteMap, outBatchSprites) { var node; switch (nodeData.type) { case "Scene3D": node = new Scene3D(); break; case "Sprite3D": node = new Sprite3D(); break; case "MeshSprite3D": node = new MeshSprite3D(); (outBatchSprites && nodeData.props.isStatic) && (outBatchSprites.push(node)); break; case "SkinnedMeshSprite3D": node = new SkinnedMeshSprite3D(); break; case "ShuriKenParticle3D": node = new ShuriKenParticle3D(); break; case "Camera": node = new Camera(); break; case "DirectionLight": node = new DirectionLight(); break; case "PointLight": node = new PointLight(); break; case "SpotLight": node = new SpotLight(); break; case "TrailSprite3D": node = new TrailSprite3D(); break; default: throw new Error("Utils3D:unidentified class type in (.lh) file."); } var childData = nodeData.child; if (childData) { for (var i = 0, n = childData.length; i < n; i++) { var child = Scene3DUtils._createSprite3DInstance(childData[i], spriteMap, outBatchSprites); node.addChild(child); } } spriteMap[nodeData.instanceID] = node; return node; } static _createComponentInstance(nodeData, spriteMap, interactMap) { var node = spriteMap[nodeData.instanceID]; node._parse(nodeData.props, spriteMap); var childData = nodeData.child; if (childData) { for (var i = 0, n = childData.length; i < n; i++) Scene3DUtils._createComponentInstance(childData[i], spriteMap, interactMap); } var componentsData = nodeData.components; if (componentsData) { for (var j = 0, m = componentsData.length; j < m; j++) { var data = componentsData[j]; var clas = Laya.ClassUtils.getRegClass(data.type); if (clas) { var component = node.addComponent(clas); component._parse(data, interactMap); } else { console.warn("Unkown component type."); } } } } static _createNodeByJson02(nodeData, outBatchSprites) { var spriteMap = {}; var interactMap = { component: [], data: [] }; var node = Scene3DUtils._createSprite3DInstance(nodeData, spriteMap, outBatchSprites); Scene3DUtils._createComponentInstance(nodeData, spriteMap, interactMap); Scene3DUtils._createInteractInstance(interactMap, spriteMap); return node; } static _createInteractInstance(interatMap, spriteMap) { var components = interatMap.component; var data = interatMap.data; for (var i = 0, n = components.length; i < n; i++) { components[i]._parseInteractive(data[i], spriteMap); } } static _parse(data, propertyParams = null, constructParams = null) { var json = data.data; var outBatchSprits = []; var sprite; switch (data.version) { case "LAYAHIERARCHY:02": sprite = Scene3DUtils._createNodeByJson02(json, outBatchSprits); break; default: sprite = Scene3DUtils._createNodeByJson(json, outBatchSprits); } StaticBatchManager.combine(sprite, outBatchSprits); return sprite; } static _parseScene(data, propertyParams = null, constructParams = null) { var json = data.data; var outBatchSprits = []; var scene; switch (data.version) { case "LAYASCENE3D:02": scene = Scene3DUtils._createNodeByJson02(json, outBatchSprits); break; default: scene = Scene3DUtils._createNodeByJson(json, outBatchSprits); } StaticBatchManager.combine(null, outBatchSprits); return scene; } static _createNodeByJson(nodeData, outBatchSprites) { var node; switch (nodeData.type) { case "Scene3D": node = new Scene3D(); break; case "Sprite3D": node = new Sprite3D(); break; case "MeshSprite3D": node = new MeshSprite3D(); (outBatchSprites && nodeData.props.isStatic) && (outBatchSprites.push(node)); break; case "SkinnedMeshSprite3D": node = new SkinnedMeshSprite3D(); break; case "ShuriKenParticle3D": node = new ShuriKenParticle3D(); break; case "Camera": node = new Camera(); break; case "DirectionLight": node = new DirectionLight(); break; case "PointLight": node = new PointLight(); break; case "SpotLight": node = new SpotLight(); break; case "TrailSprite3D": node = new TrailSprite3D(); break; default: throw new Error("Utils3D:unidentified class type in (.lh) file."); } var childData = nodeData.child; if (childData) { for (var i = 0, n = childData.length; i < n; i++) { var child = Scene3DUtils._createNodeByJson(childData[i], outBatchSprites); node.addChild(child); } } var componentsData = nodeData.components; if (componentsData) { for (var j = 0, m = componentsData.length; j < m; j++) { var data = componentsData[j]; var clas = Laya.ClassUtils.getRegClass(data.type); if (clas) { var component = node.addComponent(clas); component._parse(data); } else { console.warn("Unkown component type."); } } } node._parse(nodeData.props, null); return node; } } class LoadModelV04 { static parse(readData, version, mesh, subMeshes) { LoadModelV04._mesh = mesh; LoadModelV04._subMeshes = subMeshes; LoadModelV04._version = version; LoadModelV04._readData = readData; LoadModelV04.READ_DATA(); LoadModelV04.READ_BLOCK(); LoadModelV04.READ_STRINGS(); for (var i = 0, n = LoadModelV04._BLOCK.count; i < n; i++) { LoadModelV04._readData.pos = LoadModelV04._BLOCK.blockStarts[i]; var index = LoadModelV04._readData.getUint16(); var blockName = LoadModelV04._strings[index]; var fn = LoadModelV04["READ_" + blockName]; if (fn == null) throw new Error("model file err,no this function:" + index + " " + blockName); else fn.call(null); } LoadModelV04._strings.length = 0; LoadModelV04._readData = null; LoadModelV04._version = null; LoadModelV04._mesh = null; LoadModelV04._subMeshes = null; } static _readString() { return LoadModelV04._strings[LoadModelV04._readData.getUint16()]; } static READ_DATA() { LoadModelV04._DATA.offset = LoadModelV04._readData.getUint32(); LoadModelV04._DATA.size = LoadModelV04._readData.getUint32(); } static READ_BLOCK() { var count = LoadModelV04._BLOCK.count = LoadModelV04._readData.getUint16(); var blockStarts = LoadModelV04._BLOCK.blockStarts = []; var blockLengths = LoadModelV04._BLOCK.blockLengths = []; for (var i = 0; i < count; i++) { blockStarts.push(LoadModelV04._readData.getUint32()); blockLengths.push(LoadModelV04._readData.getUint32()); } } static READ_STRINGS() { var offset = LoadModelV04._readData.getUint32(); var count = LoadModelV04._readData.getUint16(); var prePos = LoadModelV04._readData.pos; LoadModelV04._readData.pos = offset + LoadModelV04._DATA.offset; for (var i = 0; i < count; i++) LoadModelV04._strings[i] = LoadModelV04._readData.readUTFString(); LoadModelV04._readData.pos = prePos; } static READ_MESH() { var gl = Laya.LayaGL.instance; var name = LoadModelV04._readString(); var arrayBuffer = LoadModelV04._readData.__getBuffer(); var i; var memorySize = 0; var vertexBufferCount = LoadModelV04._readData.getInt16(); var offset = LoadModelV04._DATA.offset; for (i = 0; i < vertexBufferCount; i++) { var vbStart = offset + LoadModelV04._readData.getUint32(); var vbLength = LoadModelV04._readData.getUint32(); var vbArrayBuffer = arrayBuffer.slice(vbStart, vbStart + vbLength); var vbDatas = new Float32Array(vbArrayBuffer); var bufferAttribute = LoadModelV04._readString(); var vertexDeclaration; switch (LoadModelV04._version) { case "LAYAMODEL:0301": case "LAYAMODEL:0400": vertexDeclaration = VertexMesh.getVertexDeclaration(bufferAttribute); break; case "LAYAMODEL:0401": vertexDeclaration = VertexMesh.getVertexDeclaration(bufferAttribute, false); break; default: throw new Error("LoadModelV03: unknown version."); } if (!vertexDeclaration) throw new Error("LoadModelV03: unknown vertexDeclaration."); var vertexBuffer = new VertexBuffer3D(vbDatas.length * 4, gl.STATIC_DRAW, true); vertexBuffer.vertexDeclaration = vertexDeclaration; vertexBuffer.setData(vbDatas.buffer); LoadModelV04._mesh._vertexBuffer = vertexBuffer; LoadModelV04._mesh._vertexCount += vertexBuffer._byteLength / vertexDeclaration.vertexStride; memorySize += vbDatas.length * 4; } var ibStart = offset + LoadModelV04._readData.getUint32(); var ibLength = LoadModelV04._readData.getUint32(); var ibDatas = new Uint16Array(arrayBuffer.slice(ibStart, ibStart + ibLength)); var indexBuffer = new IndexBuffer3D(exports.IndexFormat.UInt16, ibLength / 2, gl.STATIC_DRAW, true); indexBuffer.setData(ibDatas); LoadModelV04._mesh._indexBuffer = indexBuffer; memorySize += indexBuffer.indexCount * 2; LoadModelV04._mesh._setBuffer(LoadModelV04._mesh._vertexBuffer, indexBuffer); LoadModelV04._mesh._setCPUMemory(memorySize); LoadModelV04._mesh._setGPUMemory(memorySize); var boneNames = LoadModelV04._mesh._boneNames = []; var boneCount = LoadModelV04._readData.getUint16(); boneNames.length = boneCount; for (i = 0; i < boneCount; i++) boneNames[i] = LoadModelV04._strings[LoadModelV04._readData.getUint16()]; LoadModelV04._readData.pos += 8; var bindPoseDataStart = LoadModelV04._readData.getUint32(); var bindPoseDataLength = LoadModelV04._readData.getUint32(); var bindPoseDatas = new Float32Array(arrayBuffer.slice(offset + bindPoseDataStart, offset + bindPoseDataStart + bindPoseDataLength)); var bindPoseFloatCount = bindPoseDatas.length; var bindPoseBuffer = LoadModelV04._mesh._inverseBindPosesBuffer = new ArrayBuffer(bindPoseFloatCount * 4); LoadModelV04._mesh._inverseBindPoses = []; for (i = 0; i < bindPoseFloatCount; i += 16) { var inverseGlobalBindPose = new Matrix4x4(bindPoseDatas[i + 0], bindPoseDatas[i + 1], bindPoseDatas[i + 2], bindPoseDatas[i + 3], bindPoseDatas[i + 4], bindPoseDatas[i + 5], bindPoseDatas[i + 6], bindPoseDatas[i + 7], bindPoseDatas[i + 8], bindPoseDatas[i + 9], bindPoseDatas[i + 10], bindPoseDatas[i + 11], bindPoseDatas[i + 12], bindPoseDatas[i + 13], bindPoseDatas[i + 14], bindPoseDatas[i + 15], new Float32Array(bindPoseBuffer, i * 4, 16)); LoadModelV04._mesh._inverseBindPoses[i / 16] = inverseGlobalBindPose; } return true; } static READ_SUBMESH() { var arrayBuffer = LoadModelV04._readData.__getBuffer(); var subMesh = new SubMesh(LoadModelV04._mesh); LoadModelV04._readData.getInt16(); LoadModelV04._readData.getUint32(); LoadModelV04._readData.getUint32(); var ibStart = LoadModelV04._readData.getUint32(); var ibCount = LoadModelV04._readData.getUint32(); var indexBuffer = LoadModelV04._mesh._indexBuffer; subMesh._indexBuffer = indexBuffer; subMesh._setIndexRange(ibStart, ibCount); var vertexBuffer = LoadModelV04._mesh._vertexBuffer; subMesh._vertexBuffer = vertexBuffer; var offset = LoadModelV04._DATA.offset; var subIndexBufferStart = subMesh._subIndexBufferStart; var subIndexBufferCount = subMesh._subIndexBufferCount; var boneIndicesList = subMesh._boneIndicesList; var drawCount = LoadModelV04._readData.getUint16(); subIndexBufferStart.length = drawCount; subIndexBufferCount.length = drawCount; boneIndicesList.length = drawCount; var skinnedCache = LoadModelV04._mesh._skinnedMatrixCaches; var subMeshIndex = LoadModelV04._subMeshes.length; skinnedCache.length = LoadModelV04._mesh._inverseBindPoses.length; for (var i = 0; i < drawCount; i++) { subIndexBufferStart[i] = LoadModelV04._readData.getUint32(); subIndexBufferCount[i] = LoadModelV04._readData.getUint32(); var boneDicofs = LoadModelV04._readData.getUint32(); var boneDicCount = LoadModelV04._readData.getUint32(); var boneIndices = boneIndicesList[i] = new Uint16Array(arrayBuffer.slice(offset + boneDicofs, offset + boneDicofs + boneDicCount)); var boneIndexCount = boneIndices.length; for (var j = 0; j < boneIndexCount; j++) { var index = boneIndices[j]; skinnedCache[index] || (skinnedCache[index] = new skinnedMatrixCache(subMeshIndex, i, j)); } } LoadModelV04._subMeshes.push(subMesh); return true; } } LoadModelV04._BLOCK = { count: 0 }; LoadModelV04._DATA = { offset: 0, size: 0 }; LoadModelV04._strings = []; class LoadModelV05 { static parse(readData, version, mesh, subMeshes) { LoadModelV05._mesh = mesh; LoadModelV05._subMeshes = subMeshes; LoadModelV05._version = version; LoadModelV05._readData = readData; LoadModelV05.READ_DATA(); LoadModelV05.READ_BLOCK(); LoadModelV05.READ_STRINGS(); for (var i = 0, n = LoadModelV05._BLOCK.count; i < n; i++) { LoadModelV05._readData.pos = LoadModelV05._BLOCK.blockStarts[i]; var index = LoadModelV05._readData.getUint16(); var blockName = LoadModelV05._strings[index]; var fn = LoadModelV05["READ_" + blockName]; if (fn == null) throw new Error("model file err,no this function:" + index + " " + blockName); else fn.call(null); } LoadModelV05._strings.length = 0; LoadModelV05._readData = null; LoadModelV05._version = null; LoadModelV05._mesh = null; LoadModelV05._subMeshes = null; } static _readString() { return LoadModelV05._strings[LoadModelV05._readData.getUint16()]; } static READ_DATA() { LoadModelV05._DATA.offset = LoadModelV05._readData.getUint32(); LoadModelV05._DATA.size = LoadModelV05._readData.getUint32(); } static READ_BLOCK() { var count = LoadModelV05._BLOCK.count = LoadModelV05._readData.getUint16(); var blockStarts = LoadModelV05._BLOCK.blockStarts = []; var blockLengths = LoadModelV05._BLOCK.blockLengths = []; for (var i = 0; i < count; i++) { blockStarts.push(LoadModelV05._readData.getUint32()); blockLengths.push(LoadModelV05._readData.getUint32()); } } static READ_STRINGS() { var offset = LoadModelV05._readData.getUint32(); var count = LoadModelV05._readData.getUint16(); var prePos = LoadModelV05._readData.pos; LoadModelV05._readData.pos = offset + LoadModelV05._DATA.offset; for (var i = 0; i < count; i++) LoadModelV05._strings[i] = LoadModelV05._readData.readUTFString(); LoadModelV05._readData.pos = prePos; } static READ_MESH() { var gl = Laya.LayaGL.instance; var i; var memorySize = 0; var name = LoadModelV05._readString(); var reader = LoadModelV05._readData; var arrayBuffer = reader.__getBuffer(); var vertexBufferCount = reader.getInt16(); var offset = LoadModelV05._DATA.offset; for (i = 0; i < vertexBufferCount; i++) { var vbStart = offset + reader.getUint32(); var vertexCount = reader.getUint32(); var vertexFlag = LoadModelV05._readString(); var vertexDeclaration = VertexMesh.getVertexDeclaration(vertexFlag, false); var vertexStride = vertexDeclaration.vertexStride; var vertexData; var floatData; var uint8Data; var subVertexFlags = vertexFlag.split(","); var subVertexCount = subVertexFlags.length; var mesh = LoadModelV05._mesh; switch (LoadModelV05._version) { case "LAYAMODEL:05": case "LAYAMODEL:0501": vertexData = arrayBuffer.slice(vbStart, vbStart + vertexCount * vertexStride); floatData = new Float32Array(vertexData); uint8Data = new Uint8Array(vertexData); break; case "LAYAMODEL:COMPRESSION_05": case "LAYAMODEL:COMPRESSION_0501": vertexData = new ArrayBuffer(vertexStride * vertexCount); floatData = new Float32Array(vertexData); uint8Data = new Uint8Array(vertexData); var lastPosition = reader.pos; reader.pos = vbStart; for (var j = 0; j < vertexCount; j++) { var subOffset; var verOffset = j * vertexStride; for (var k = 0; k < subVertexCount; k++) { switch (subVertexFlags[k]) { case "POSITION": subOffset = verOffset / 4; floatData[subOffset] = HalfFloatUtils.convertToNumber(reader.getUint16()); floatData[subOffset + 1] = HalfFloatUtils.convertToNumber(reader.getUint16()); floatData[subOffset + 2] = HalfFloatUtils.convertToNumber(reader.getUint16()); verOffset += 12; break; case "NORMAL": subOffset = verOffset / 4; floatData[subOffset] = reader.getUint8() / 127.5 - 1; floatData[subOffset + 1] = reader.getUint8() / 127.5 - 1; floatData[subOffset + 2] = reader.getUint8() / 127.5 - 1; verOffset += 12; break; case "COLOR": subOffset = verOffset / 4; floatData[subOffset] = reader.getUint8() / 255; floatData[subOffset + 1] = reader.getUint8() / 255; floatData[subOffset + 2] = reader.getUint8() / 255; floatData[subOffset + 3] = reader.getUint8() / 255; verOffset += 16; break; case "UV": subOffset = verOffset / 4; floatData[subOffset] = HalfFloatUtils.convertToNumber(reader.getUint16()); floatData[subOffset + 1] = HalfFloatUtils.convertToNumber(reader.getUint16()); verOffset += 8; break; case "UV1": subOffset = verOffset / 4; floatData[subOffset] = HalfFloatUtils.convertToNumber(reader.getUint16()); floatData[subOffset + 1] = HalfFloatUtils.convertToNumber(reader.getUint16()); verOffset += 8; break; case "BLENDWEIGHT": subOffset = verOffset / 4; floatData[subOffset] = reader.getUint8() / 255; floatData[subOffset + 1] = reader.getUint8() / 255; floatData[subOffset + 2] = reader.getUint8() / 255; floatData[subOffset + 3] = reader.getUint8() / 255; verOffset += 16; break; case "BLENDINDICES": uint8Data[verOffset] = reader.getUint8(); uint8Data[verOffset + 1] = reader.getUint8(); uint8Data[verOffset + 2] = reader.getUint8(); uint8Data[verOffset + 3] = reader.getUint8(); verOffset += 4; break; case "TANGENT": subOffset = verOffset / 4; floatData[subOffset] = reader.getUint8() / 127.5 - 1; floatData[subOffset + 1] = reader.getUint8() / 127.5 - 1; floatData[subOffset + 2] = reader.getUint8() / 127.5 - 1; floatData[subOffset + 3] = reader.getUint8() / 127.5 - 1; verOffset += 16; break; } } } reader.pos = lastPosition; break; } var vertexBuffer = new VertexBuffer3D(vertexData.byteLength, gl.STATIC_DRAW, true); vertexBuffer.vertexDeclaration = vertexDeclaration; vertexBuffer.setData(vertexData); var vertexCount = vertexBuffer._byteLength / vertexDeclaration.vertexStride; if (vertexCount > 65535) mesh._indexFormat = exports.IndexFormat.UInt32; else mesh._indexFormat = exports.IndexFormat.UInt16; mesh._vertexBuffer = vertexBuffer; mesh._vertexCount += vertexCount; memorySize += floatData.length * 4; } var ibStart = offset + reader.getUint32(); var ibLength = reader.getUint32(); var ibDatas; if (mesh.indexFormat == exports.IndexFormat.UInt32) ibDatas = new Uint32Array(arrayBuffer.slice(ibStart, ibStart + ibLength)); else ibDatas = new Uint16Array(arrayBuffer.slice(ibStart, ibStart + ibLength)); var indexBuffer = new IndexBuffer3D(mesh.indexFormat, ibDatas.length, gl.STATIC_DRAW, true); indexBuffer.setData(ibDatas); mesh._indexBuffer = indexBuffer; mesh._setBuffer(mesh._vertexBuffer, indexBuffer); memorySize += indexBuffer.indexCount * 2; mesh._setCPUMemory(memorySize); mesh._setGPUMemory(memorySize); if (LoadModelV05._version == "LAYAMODEL:0501" || LoadModelV05._version == "LAYAMODEL:COMPRESSION_0501") { var bounds = mesh.bounds; var min = bounds.getMin(); var max = bounds.getMax(); min.setValue(reader.getFloat32(), reader.getFloat32(), reader.getFloat32()); max.setValue(reader.getFloat32(), reader.getFloat32(), reader.getFloat32()); bounds.setMin(min); bounds.setMax(max); mesh.bounds = bounds; } var boneNames = mesh._boneNames = []; var boneCount = reader.getUint16(); boneNames.length = boneCount; for (i = 0; i < boneCount; i++) boneNames[i] = LoadModelV05._strings[reader.getUint16()]; var bindPoseDataStart = reader.getUint32(); var bindPoseDataLength = reader.getUint32(); var bindPoseDatas = new Float32Array(arrayBuffer.slice(offset + bindPoseDataStart, offset + bindPoseDataStart + bindPoseDataLength)); var bindPoseFloatCount = bindPoseDatas.length; var bindPoseBuffer = mesh._inverseBindPosesBuffer = new ArrayBuffer(bindPoseFloatCount * 4); mesh._inverseBindPoses = []; for (i = 0; i < bindPoseFloatCount; i += 16) { var inverseGlobalBindPose = new Matrix4x4(bindPoseDatas[i + 0], bindPoseDatas[i + 1], bindPoseDatas[i + 2], bindPoseDatas[i + 3], bindPoseDatas[i + 4], bindPoseDatas[i + 5], bindPoseDatas[i + 6], bindPoseDatas[i + 7], bindPoseDatas[i + 8], bindPoseDatas[i + 9], bindPoseDatas[i + 10], bindPoseDatas[i + 11], bindPoseDatas[i + 12], bindPoseDatas[i + 13], bindPoseDatas[i + 14], bindPoseDatas[i + 15], new Float32Array(bindPoseBuffer, i * 4, 16)); mesh._inverseBindPoses[i / 16] = inverseGlobalBindPose; } return true; } static READ_SUBMESH() { var reader = LoadModelV05._readData; var arrayBuffer = reader.__getBuffer(); var subMesh = new SubMesh(LoadModelV05._mesh); reader.getInt16(); var ibStart = reader.getUint32(); var ibCount = reader.getUint32(); var indexBuffer = LoadModelV05._mesh._indexBuffer; subMesh._indexBuffer = indexBuffer; subMesh._setIndexRange(ibStart, ibCount); var vertexBuffer = LoadModelV05._mesh._vertexBuffer; subMesh._vertexBuffer = vertexBuffer; var offset = LoadModelV05._DATA.offset; var subIndexBufferStart = subMesh._subIndexBufferStart; var subIndexBufferCount = subMesh._subIndexBufferCount; var boneIndicesList = subMesh._boneIndicesList; var drawCount = reader.getUint16(); subIndexBufferStart.length = drawCount; subIndexBufferCount.length = drawCount; boneIndicesList.length = drawCount; var skinnedCache = LoadModelV05._mesh._skinnedMatrixCaches; var subMeshIndex = LoadModelV05._subMeshes.length; skinnedCache.length = LoadModelV05._mesh._inverseBindPoses.length; for (var i = 0; i < drawCount; i++) { subIndexBufferStart[i] = reader.getUint32(); subIndexBufferCount[i] = reader.getUint32(); var boneDicofs = reader.getUint32(); var boneDicCount = reader.getUint32(); var boneIndices = boneIndicesList[i] = new Uint16Array(arrayBuffer.slice(offset + boneDicofs, offset + boneDicofs + boneDicCount)); for (var j = 0, m = boneIndices.length; j < m; j++) { var index = boneIndices[j]; skinnedCache[index] || (skinnedCache[index] = new skinnedMatrixCache(subMeshIndex, i, j)); } } LoadModelV05._subMeshes.push(subMesh); return true; } } LoadModelV05._BLOCK = { count: 0 }; LoadModelV05._DATA = { offset: 0, size: 0 }; LoadModelV05._strings = []; class MeshReader { static _parse(data, propertyParams = null, constructParams = null) { var mesh = new Mesh(); MeshReader.read(data, mesh, mesh._subMeshes); return mesh; } static read(data, mesh, subMeshes) { var readData = new Laya.Byte(data); readData.pos = 0; var version = readData.readUTFString(); switch (version) { case "LAYAMODEL:0301": case "LAYAMODEL:0400": case "LAYAMODEL:0401": LoadModelV04.parse(readData, version, mesh, subMeshes); break; case "LAYAMODEL:05": case "LAYAMODEL:COMPRESSION_05": case "LAYAMODEL:0501": case "LAYAMODEL:COMPRESSION_0501": LoadModelV05.parse(readData, version, mesh, subMeshes); break; default: throw new Error("MeshReader: unknown mesh version."); } mesh._setSubMeshes(subMeshes); if (version != "LAYAMODEL:0501" && version != "LAYAMODEL:COMPRESSION_0501") mesh.calculateBounds(); } } var SkyPanoramicFS = "#ifdef GL_FRAGMENT_PRECISION_HIGH\r\n\tprecision highp float;\r\n#else\r\n\tprecision mediump float;\r\n#endif\r\n\r\n#define PI 3.14159265359\r\n#include \"Lighting.glsl\";\r\n\r\nuniform sampler2D u_Texture;\r\nuniform vec4 u_TextureHDRParams;\r\nuniform vec4 u_TintColor;\r\n\r\nvarying vec3 v_Texcoord;\r\nvarying vec2 v_Image180ScaleAndCutoff;\r\nvarying vec4 v_Layout3DScaleAndOffset;\r\n\r\nvec2 ToRadialCoords(vec3 coords)\r\n{\r\n\tvec3 normalizedCoords = normalize(coords);\r\n\tfloat latitude = acos(normalizedCoords.y);\r\n\tfloat longitude = atan(normalizedCoords.z,normalizedCoords.x);\r\n\tvec2 sphereCoords = vec2(longitude, latitude) * vec2(0.5/PI, 1.0/PI);\r\n\treturn vec2(0.5,1.0) - sphereCoords;\r\n}\r\n\r\n\r\nvoid main()\r\n{\t\r\n\tvec2 tc = ToRadialCoords(v_Texcoord);\r\n\tif (tc.x > v_Image180ScaleAndCutoff.y)\r\n\t\tgl_FragColor=vec4(0,0,0,1);\r\n\ttc.x = mod(tc.x*v_Image180ScaleAndCutoff.x, 1.0);\r\n\ttc = (tc + v_Layout3DScaleAndOffset.xy) * v_Layout3DScaleAndOffset.zw;\r\n\r\n\tmediump vec4 tex = texture2D (u_Texture, tc);\r\n\tmediump vec3 c = decodeHDR (tex, u_TextureHDRParams.x);\r\n\tc = c * u_TintColor.rgb * 2.0;//Gamma Space is 2.0,linear space is 4.59479380\r\n\tgl_FragColor=vec4(c, 1.0);\r\n}\r\n\r\n"; var SkyPanoramicVS = "#include \"Lighting.glsl\";\r\n\r\n#define PI 3.14159265359\r\n\r\nattribute vec4 a_Position;\r\n\r\nuniform mat4 u_ViewProjection;\r\nuniform float u_Rotation;\r\n\r\nvarying vec3 v_Texcoord;\r\nvarying vec2 v_Image180ScaleAndCutoff;\r\nvarying vec4 v_Layout3DScaleAndOffset;\r\n\r\nvec4 rotateAroundYInDegrees (vec4 vertex, float degrees)\r\n{\r\n\tfloat angle = degrees * PI / 180.0;\r\n\tfloat sina=sin(angle);\r\n\tfloat cosa=cos(angle);\r\n\tmat2 m = mat2(cosa, -sina, sina, cosa);\r\n\treturn vec4(m*vertex.xz, vertex.yw).xzyw;\r\n}\r\n\r\n\t\t\r\nvoid main()\r\n{\r\n\tvec4 position = rotateAroundYInDegrees(a_Position, u_Rotation);\r\n\tgl_Position = u_ViewProjection*position;\r\n\r\n\tv_Texcoord=vec3(-a_Position.x,-a_Position.y,a_Position.z);// NOTE: -a_Position.x convert coords system\r\n\r\n\t// Calculate constant horizontal scale and cutoff for 180 (vs 360) image type\r\n\tv_Image180ScaleAndCutoff = vec2(1.0, 1.0);// 360 degree mode\r\n\r\n\t// Calculate constant scale and offset for 3D layouts\r\n\tv_Layout3DScaleAndOffset = vec4(0,0,1,1);\r\n}\r\n"; class SkyPanoramicMaterial extends Material { constructor() { super(); this._exposure = 1.0; this._textureDecodeFormat = Laya.TextureDecodeFormat.Normal; this._textureHDRParams = new Vector4(1.0, 0.0, 0.0, 1.0); this.setShaderName("SkyPanoramic"); var shaderValues = this._shaderValues; shaderValues.setVector(SkyPanoramicMaterial.TINTCOLOR, new Vector4(0.5, 0.5, 0.5, 0.5)); shaderValues.setNumber(SkyPanoramicMaterial.ROTATION, 0.0); shaderValues.setVector(SkyPanoramicMaterial.TEXTURE_HDR_PARAMS, this._textureHDRParams); } static __init__() { var attributeMap = { 'a_Position': VertexMesh.MESH_POSITION0 }; var uniformMap = { 'u_TintColor': Shader3D.PERIOD_MATERIAL, 'u_TextureHDRParams': Shader3D.PERIOD_MATERIAL, 'u_Rotation': Shader3D.PERIOD_MATERIAL, 'u_Texture': Shader3D.PERIOD_MATERIAL, 'u_ViewProjection': Shader3D.PERIOD_CAMERA }; var shader = Shader3D.add("SkyPanoramic"); var subShader = new SubShader(attributeMap, uniformMap); shader.addSubShader(subShader); subShader.addShaderPass(SkyPanoramicVS, SkyPanoramicFS); } get tintColor() { return this._shaderValues.getVector(SkyPanoramicMaterial.TINTCOLOR); } set tintColor(value) { this._shaderValues.setVector(SkyPanoramicMaterial.TINTCOLOR, value); } get exposure() { return this._exposure; } set exposure(value) { if (this._exposure !== value) { this._exposure = value; if (this._textureDecodeFormat == Laya.TextureDecodeFormat.RGBM) this._textureHDRParams.x = value * Laya.BaseTexture._rgbmRange; else this._textureHDRParams.x = value; } } get rotation() { return this._shaderValues.getNumber(SkyPanoramicMaterial.ROTATION); } set rotation(value) { this._shaderValues.setNumber(SkyPanoramicMaterial.ROTATION, value); } get panoramicTexture() { return this._shaderValues.getTexture(SkyPanoramicMaterial.TEXTURE); } set panoramicTexture(value) { this._shaderValues.setTexture(SkyPanoramicMaterial.TEXTURE, value); } get panoramicTextureDecodeFormat() { return this._textureDecodeFormat; } set panoramicTextureDecodeFormat(value) { if (this._textureDecodeFormat !== value) { this._textureDecodeFormat = value; if (value == Laya.TextureDecodeFormat.RGBM) this._textureHDRParams.x = this._exposure * Laya.BaseTexture._rgbmRange; else this._textureHDRParams.x = this._exposure; } } } SkyPanoramicMaterial.TINTCOLOR = Shader3D.propertyNameToID("u_TintColor"); SkyPanoramicMaterial.EXPOSURE = Shader3D.propertyNameToID("u_Exposure"); SkyPanoramicMaterial.ROTATION = Shader3D.propertyNameToID("u_Rotation"); SkyPanoramicMaterial.TEXTURE = Shader3D.propertyNameToID("u_Texture"); SkyPanoramicMaterial.TEXTURE_HDR_PARAMS = Shader3D.propertyNameToID("u_TextureHDRParams"); class ConstraintComponent extends Laya.Component { constructor(constraintType) { super(); this._anchor = new Vector3(); this._connectAnchor = new Vector3(); this._feedbackEnabled = false; this._getJointFeedBack = false; this._currentForce = new Vector3(); this._currentTorque = new Vector3(); this._constraintType = constraintType; var bt = Physics3D._bullet; this._btframATrans = bt.btTransform_create(); this._btframBTrans = bt.btTransform_create(); bt.btTransform_setIdentity(this._btframATrans); bt.btTransform_setIdentity(this._btframBTrans); this._btframAPos = bt.btVector3_create(0, 0, 0); this._btframBPos = bt.btVector3_create(0, 0, 0); bt.btTransform_setOrigin(this._btframATrans, this._btframAPos); bt.btTransform_setOrigin(this._btframBTrans, this._btframBPos); this._breakForce = -1; this._breakTorque = -1; } get enabled() { return super.enabled; } set enabled(value) { super.enabled = value; } get appliedImpulse() { if (!this._feedbackEnabled) { this._btConstraint.EnableFeedback(true); this._feedbackEnabled = true; } return this._btConstraint.AppliedImpulse; } set connectedBody(value) { this._connectedBody = value; value.constaintRigidbodyB = this; } get connectedBody() { return this._connectedBody; } get ownBody() { return this._ownBody; } set ownBody(value) { this._ownBody = value; value.constaintRigidbodyA = this; } get currentForce() { if (!this._getJointFeedBack) this._getFeedBackInfo(); return this._currentForce; } get currentTorque() { if (!this._getJointFeedBack) this._getFeedBackInfo(); return this._currentTorque; } get breakForce() { return this._breakForce; } set breakForce(value) { this._breakForce = value; } get breakTorque() { return this._breakTorque; } set breakTorque(value) { this._breakTorque = value; } set anchor(value) { value.cloneTo(this._anchor); this.setFrames(); } get anchor() { return this._anchor; } set connectAnchor(value) { value.cloneTo(this._connectAnchor); this.setFrames(); } get connectAnchor() { return this._connectAnchor; } setOverrideNumSolverIterations(overideNumIterations) { var bt = Physics3D._bullet; bt.btTypedConstraint_setOverrideNumSolverIterations(this._btConstraint, overideNumIterations); } setConstraintEnabled(enable) { var bt = Physics3D._bullet; bt.btTypedConstraint_setEnabled(this._btConstraint, enable); } _onEnable() { super._onEnable(); this.enabled = true; } _onDisable() { super._onDisable(); this.enabled = false; } setFrames() { var bt = Physics3D._bullet; bt.btVector3_setValue(this._btframAPos, -this._anchor.x, this.anchor.y, this.anchor.z); bt.btVector3_setValue(this._btframBPos, -this._connectAnchor.x, this._connectAnchor.y, this._connectAnchor.z); bt.btTransform_setOrigin(this._btframATrans, this._btframAPos); bt.btTransform_setOrigin(this._btframBTrans, this._btframBPos); } _addToSimulation() { } _removeFromSimulation() { } _createConstraint() { } setConnectRigidBody(ownerRigid, connectRigidBody) { var ownerCanInSimulation = (ownerRigid) && (!!(ownerRigid._simulation && ownerRigid._enabled && ownerRigid.colliderShape)); var connectCanInSimulation = (connectRigidBody) && (!!(connectRigidBody._simulation && connectRigidBody._enabled && connectRigidBody.colliderShape)); if (!(ownerCanInSimulation && connectCanInSimulation)) throw "ownerRigid or connectRigidBody is not in Simulation"; if (ownerRigid != this._ownBody || connectRigidBody != this._connectedBody) { var canInSimulation = !!(this.enabled && this._simulation); canInSimulation && this._removeFromSimulation(); this._ownBody = ownerRigid; this._connectedBody = connectRigidBody; this._ownBody.constaintRigidbodyA = this; this._connectedBody.constaintRigidbodyB = this; this._createConstraint(); } } getcurrentForce(out) { if (!this._btJointFeedBackObj) throw "this Constraint is not simulation"; var bt = Physics3D._bullet; var applyForce = bt.btJointFeedback_getAppliedForceBodyA(this._btJointFeedBackObj); out.setValue(bt.btVector3_x(applyForce), bt.btVector3_y(applyForce), bt.btVector3_z(applyForce)); return; } getcurrentTorque(out) { if (!this._btJointFeedBackObj) throw "this Constraint is not simulation"; var bt = Physics3D._bullet; var applyTorque = bt.btJointFeedback_getAppliedTorqueBodyA(this._btJointFeedBackObj); out.setValue(bt.btVector3_x(applyTorque), bt.btVector3_y(applyTorque), bt.btVector3_z(applyTorque)); return; } _onDestroy() { var physics3D = Physics3D._bullet; this._removeFromSimulation(); if (this._btConstraint && this._btJointFeedBackObj && this._simulation) { physics3D.btTypedConstraint_destroy(this._btConstraint); physics3D.btJointFeedback_destroy(this._btJointFeedBackObj); this._btJointFeedBackObj = null; this._btConstraint = null; } super._onDisable(); } _isBreakConstrained() { this._getJointFeedBack = false; if (this.breakForce == -1 && this.breakTorque == -1) return false; this._getFeedBackInfo(); var isBreakForce = this._breakForce != -1 && (Vector3.scalarLength(this._currentForce) > this._breakForce); var isBreakTorque = this._breakTorque != -1 && (Vector3.scalarLength(this._currentTorque) > this._breakTorque); if (isBreakForce || isBreakTorque) { this._breakConstrained(); return true; } return false; } _parse(data) { this._anchor.fromArray(data.anchor); this._connectAnchor.fromArray(data.connectAnchor); this.setFrames(); } _getFeedBackInfo() { var bt = Physics3D._bullet; var applyForce = bt.btJointFeedback_getAppliedForceBodyA(this._btJointFeedBackObj); var applyTorque = bt.btJointFeedback_getAppliedTorqueBodyA(this._btJointFeedBackObj); this._currentTorque.setValue(bt.btVector3_x(applyTorque), bt.btVector3_y(applyTorque), bt.btVector3_z(applyTorque)); this._currentForce.setValue(bt.btVector3_x(applyForce), bt.btVector3_y(applyForce), bt.btVector3_z(applyForce)); this._getJointFeedBack = true; } _breakConstrained() { this.ownBody.constaintRigidbodyA = null; this.connectedBody.constaintRigidbodyB = null; this.destroy(); } } ConstraintComponent.CONSTRAINT_POINT2POINT_CONSTRAINT_TYPE = 3; ConstraintComponent.CONSTRAINT_HINGE_CONSTRAINT_TYPE = 4; ConstraintComponent.CONSTRAINT_CONETWIST_CONSTRAINT_TYPE = 5; ConstraintComponent.CONSTRAINT_D6_CONSTRAINT_TYPE = 6; ConstraintComponent.CONSTRAINT_SLIDER_CONSTRAINT_TYPE = 7; ConstraintComponent.CONSTRAINT_CONTACT_CONSTRAINT_TYPE = 8; ConstraintComponent.CONSTRAINT_D6_SPRING_CONSTRAINT_TYPE = 9; ConstraintComponent.CONSTRAINT_GEAR_CONSTRAINT_TYPE = 10; ConstraintComponent.CONSTRAINT_FIXED_CONSTRAINT_TYPE = 11; ConstraintComponent.CONSTRAINT_MAX_CONSTRAINT_TYPE = 12; ConstraintComponent.CONSTRAINT_CONSTRAINT_ERP = 1; ConstraintComponent.CONSTRAINT_CONSTRAINT_STOP_ERP = 2; ConstraintComponent.CONSTRAINT_CONSTRAINT_CFM = 3; ConstraintComponent.CONSTRAINT_CONSTRAINT_STOP_CFM = 4; ConstraintComponent.tempForceV3 = new Vector3(); class FixedConstraint extends ConstraintComponent { constructor() { super(ConstraintComponent.CONSTRAINT_FIXED_CONSTRAINT_TYPE); this.breakForce = -1; this.breakTorque = -1; } _addToSimulation() { this._simulation && this._simulation.addConstraint(this, this.enabled); } _removeFromSimulation() { this._simulation.removeConstraint(this); this._simulation = null; } _createConstraint() { if (this.ownBody && this.ownBody._simulation && this.connectedBody && this.connectedBody._simulation) { var bt = Physics3D._bullet; this._btConstraint = bt.btFixedConstraint_create(this.ownBody.btColliderObject, this._btframATrans, this.connectedBody.btColliderObject, this._btframBTrans); this._btJointFeedBackObj = bt.btJointFeedback_create(this._btConstraint); bt.btTypedConstraint_setJointFeedback(this._btConstraint, this._btJointFeedBackObj); this._simulation = this.owner._scene.physicsSimulation; this._addToSimulation(); Physics3D._bullet.btTypedConstraint_setEnabled(this._btConstraint, true); } } _onAdded() { super._onAdded(); } _onEnable() { if (!this._btConstraint) return; super._onEnable(); if (this._btConstraint) Physics3D._bullet.btTypedConstraint_setEnabled(this._btConstraint, true); } _onDisable() { super._onDisable(); if (!this.connectedBody) this._removeFromSimulation(); if (this._btConstraint) Physics3D._bullet.btTypedConstraint_setEnabled(this._btConstraint, false); } _onDestroy() { super._onDestroy(); } _parse(data, interactMap = null) { super._parse(data); if (data.rigidbodyID != -1 && data.connectRigidbodyID != -1) { interactMap.component.push(this); interactMap.data.push(data); } (data.breakForce != undefined) && (this.breakForce = data.breakForce); (data.breakTorque != undefined) && (this.breakTorque = data.breakTorque); } _parseInteractive(data = null, spriteMap = null) { var rigidBodySprite = spriteMap[data.rigidbodyID]; var rigidBody = rigidBodySprite.getComponent(Rigidbody3D); var connectSprite = spriteMap[data.connectRigidbodyID]; var connectRigidbody = connectSprite.getComponent(Rigidbody3D); this.ownBody = rigidBody; this.connectedBody = connectRigidbody; } _cloneTo(dest) { } } class ConfigurableConstraint extends ConstraintComponent { constructor() { super(ConstraintComponent.CONSTRAINT_D6_SPRING_CONSTRAINT_TYPE); this._axis = new Vector3(); this._secondaryAxis = new Vector3(); this._minLinearLimit = new Vector3(); this._maxLinearLimit = new Vector3(); this._minAngularLimit = new Vector3(); this._maxAngularLimit = new Vector3(); this._linearLimitSpring = new Vector3(); this._angularLimitSpring = new Vector3(); this._linearBounce = new Vector3(); this._angularBounce = new Vector3(); this._linearDamp = new Vector3(); this._angularDamp = new Vector3(); this._xMotion = 0; this._yMotion = 0; this._zMotion = 0; this._angularXMotion = 0; this._angularYMotion = 0; this._angularZMotion = 0; var bt = Physics3D._bullet; this._btAxis = bt.btVector3_create(-1.0, 0.0, 0.0); this._btSecondaryAxis = bt.btVector3_create(0.0, 1.0, 0.0); } get axis() { return this._axis; } get secondaryAxis() { return this._secondaryAxis; } set maxAngularLimit(value) { value.cloneTo(this._maxAngularLimit); } set minAngularLimit(value) { value.cloneTo(this._minAngularLimit); } get maxAngularLimit() { return this._maxAngularLimit; } get minAngularLimit() { return this._minAngularLimit; } set maxLinearLimit(value) { value.cloneTo(this._maxLinearLimit); } set minLinearLimit(value) { value.cloneTo(this._minLinearLimit); } get maxLinearLimit() { return this._maxLinearLimit; } get minLinearLimit() { return this._minLinearLimit; } set XMotion(value) { if (this._xMotion != value) { this._xMotion = value; this.setLimit(ConfigurableConstraint.MOTION_LINEAR_INDEX_X, value, -this._maxLinearLimit.x, -this._minLinearLimit.x); } } get XMotion() { return this._xMotion; } set YMotion(value) { if (this._yMotion != value) { this._yMotion = value; this.setLimit(ConfigurableConstraint.MOTION_LINEAR_INDEX_Y, value, this._minLinearLimit.y, this._maxLinearLimit.y); } } get YMotion() { return this._yMotion; } set ZMotion(value) { if (this._zMotion != value) { this._zMotion = value; this.setLimit(ConfigurableConstraint.MOTION_LINEAR_INDEX_Z, value, this._minLinearLimit.z, this._maxLinearLimit.z); } } get ZMotion() { return this._zMotion; } set angularXMotion(value) { if (this._angularXMotion != value) { this._angularXMotion = value; this.setLimit(ConfigurableConstraint.MOTION_ANGULAR_INDEX_X, value, -this._maxAngularLimit.x, -this._minAngularLimit.x); } } get angularXMotion() { return this._angularXMotion; } set angularYMotion(value) { if (this._angularYMotion != value) { this._angularYMotion = value; this.setLimit(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y, value, this._minAngularLimit.y, this._maxAngularLimit.y); } } get angularYMotion() { return this._angularYMotion; } set angularZMotion(value) { if (this._angularZMotion != value) { this._angularZMotion = value; this.setLimit(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z, value, this._minAngularLimit.z, this._maxAngularLimit.z); } } get angularZMotion() { return this._angularZMotion; } set linearLimitSpring(value) { if (!Vector3.equals(this._linearLimitSpring, value)) { value.cloneTo(this._linearLimitSpring); this.setSpring(ConfigurableConstraint.MOTION_LINEAR_INDEX_X, value.x); this.setSpring(ConfigurableConstraint.MOTION_LINEAR_INDEX_Y, value.y); this.setSpring(ConfigurableConstraint.MOTION_LINEAR_INDEX_Z, value.z); } } get linearLimitSpring() { return this._linearLimitSpring; } set angularLimitSpring(value) { if (!Vector3.equals(this._angularLimitSpring, value)) { value.cloneTo(this._angularLimitSpring); this.setSpring(ConfigurableConstraint.MOTION_ANGULAR_INDEX_X, value.x); this.setSpring(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y, value.y); this.setSpring(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z, value.z); } } get angularLimitSpring() { return this._angularLimitSpring; } set linearBounce(value) { if (!Vector3.equals(this._linearBounce, value)) { value.cloneTo(this._linearBounce); this.setBounce(ConfigurableConstraint.MOTION_LINEAR_INDEX_X, value.x); this.setBounce(ConfigurableConstraint.MOTION_LINEAR_INDEX_Y, value.y); this.setBounce(ConfigurableConstraint.MOTION_LINEAR_INDEX_Z, value.z); } } get linearBounce() { return this._linearBounce; } set angularBounce(value) { if (!Vector3.equals(this._angularBounce, value)) { value.cloneTo(this._angularBounce); this.setBounce(ConfigurableConstraint.MOTION_ANGULAR_INDEX_X, value.x); this.setBounce(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y, value.y); this.setBounce(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z, value.z); } } get angularBounce() { return this._angularBounce; } set linearDamp(value) { if (!Vector3.equals(this._linearDamp, value)) { value.cloneTo(this._linearDamp); this.setDamping(ConfigurableConstraint.MOTION_LINEAR_INDEX_X, value.x); this.setDamping(ConfigurableConstraint.MOTION_LINEAR_INDEX_Y, value.y); this.setDamping(ConfigurableConstraint.MOTION_LINEAR_INDEX_Z, value.z); } } get linearDamp() { return this._linearDamp; } set angularDamp(value) { if (!Vector3.equals(this._angularDamp, value)) { value.cloneTo(this._angularDamp); this.setDamping(ConfigurableConstraint.MOTION_ANGULAR_INDEX_X, value.x); this.setDamping(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y, value.y); this.setDamping(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z, value.z); } } get angularDamp() { return this._angularDamp; } set anchor(value) { value.cloneTo(this._anchor); this.setFrames(); } get anchor() { return this._anchor; } set connectAnchor(value) { value.cloneTo(this._connectAnchor); this.setFrames(); } get connectAnchor() { return this._connectAnchor; } setAxis(axis, secondaryAxis) { if (!this._btConstraint) return; var bt = Physics3D._bullet; this._axis.setValue(axis.x, axis.y, axis.y); this._secondaryAxis.setValue(secondaryAxis.x, secondaryAxis.y, secondaryAxis.z); this._btAxis = bt.btVector3_setValue(-axis.x, axis.y, axis.z); this._btSecondaryAxis = bt.btVector3_setValue(-secondaryAxis.x, secondaryAxis.y, secondaryAxis.z); bt.btGeneric6DofSpring2Constraint_setAxis(this._btConstraint, this._btAxis, this._btSecondaryAxis); } setLimit(axis, motionType, low, high) { if (!this._btConstraint) return; var bt = Physics3D._bullet; switch (motionType) { case ConfigurableConstraint.CONFIG_MOTION_TYPE_LOCKED: bt.btGeneric6DofSpring2Constraint_setLimit(this._btConstraint, axis, 0, 0); break; case ConfigurableConstraint.CONFIG_MOTION_TYPE_LIMITED: if (low < high) bt.btGeneric6DofSpring2Constraint_setLimit(this._btConstraint, axis, low, high); break; case ConfigurableConstraint.CONFIG_MOTION_TYPE_FREE: bt.btGeneric6DofSpring2Constraint_setLimit(this._btConstraint, axis, 1, 0); break; default: throw "No Type of Axis Motion"; } } setSpring(axis, springValue, limitIfNeeded = true) { if (!this._btConstraint) return; var bt = Physics3D._bullet; var enableSpring = springValue > 0; bt.btGeneric6DofSpring2Constraint_enableSpring(this._btConstraint, axis, enableSpring); if (enableSpring) bt.btGeneric6DofSpring2Constraint_setStiffness(this._btConstraint, axis, springValue, limitIfNeeded); } setBounce(axis, bounce) { if (!this._btConstraint) return; var bt = Physics3D._bullet; bounce = bounce <= 0 ? 0 : bounce; bt.btGeneric6DofSpring2Constraint_setBounce(this._btConstraint, axis, bounce); } setDamping(axis, damp, limitIfNeeded = true) { if (!this._btConstraint) return; var bt = Physics3D._bullet; damp = damp <= 0 ? 0 : damp; bt.btGeneric6DofSpring2Constraint_setDamping(this._btConstraint, axis, damp, limitIfNeeded); } setEquilibriumPoint(axis, equilibriumPoint) { var bt = Physics3D._bullet; bt.btGeneric6DofSpring2Constraint_setEquilibriumPoint(this._btConstraint, axis, equilibriumPoint); } enableMotor(axis, isEnableMotor) { var bt = Physics3D._bullet; bt.btGeneric6DofSpring2Constraint_enableMotor(this._btConstraint, axis, isEnableMotor); } setServo(axis, onOff) { var bt = Physics3D._bullet; bt.btGeneric6DofSpring2Constraint_setServo(this._btConstraint, axis, onOff); } setTargetVelocity(axis, velocity) { var bt = Physics3D._bullet; bt.btGeneric6DofSpring2Constraint_setTargetVelocity(this._btConstraint, axis, velocity); } setTargetPosition(axis, target) { var bt = Physics3D._bullet; bt.btGeneric6DofSpring2Constraint_setServoTarget(this._btConstraint, axis, target); } setMaxMotorForce(axis, force) { var bt = Physics3D._bullet; bt.btGeneric6DofSpring2Constraint_setMaxMotorForce(this._btConstraint, axis, force); } setParam(axis, constraintParams, value) { var bt = Physics3D._bullet; bt.btTypedConstraint_setParam(this._btConstraint, axis, constraintParams, value); } setFrames() { super.setFrames(); var bt = Physics3D._bullet; if (!this._btConstraint) return; bt.btGeneric6DofSpring2Constraint_setFrames(this._btConstraint, this._btframATrans, this._btframBTrans); } _addToSimulation() { this._simulation && this._simulation.addConstraint(this, this.enabled); } _removeFromSimulation() { this._simulation.removeConstraint(this); this._simulation = null; } _createConstraint() { var bt = Physics3D._bullet; this._btConstraint = bt.btGeneric6DofSpring2Constraint_create(this.ownBody.btColliderObject, this._btframAPos, this.connectedBody.btColliderObject, this._btframBPos, ConfigurableConstraint.RO_XYZ); this._btJointFeedBackObj = bt.btJointFeedback_create(this._btConstraint); bt.btTypedConstraint_setJointFeedback(this._btConstraint, this._btJointFeedBackObj); this._simulation = this.owner._scene.physicsSimulation; this._initAllConstraintInfo(); this._addToSimulation(); Physics3D._bullet.btTypedConstraint_setEnabled(this._btConstraint, true); } _initAllConstraintInfo() { this.setLimit(ConfigurableConstraint.MOTION_LINEAR_INDEX_X, this._xMotion, -this._maxLinearLimit.x, -this._minLinearLimit.x); this.setLimit(ConfigurableConstraint.MOTION_LINEAR_INDEX_Y, this._yMotion, this._minLinearLimit.y, this._maxLinearLimit.y); this.setLimit(ConfigurableConstraint.MOTION_LINEAR_INDEX_Z, this._zMotion, this._minLinearLimit.z, this._maxLinearLimit.z); this.setLimit(ConfigurableConstraint.MOTION_ANGULAR_INDEX_X, this._angularXMotion, -this._maxAngularLimit.x, -this._minAngularLimit.x); this.setLimit(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y, this._angularYMotion, this._minAngularLimit.y, this._maxAngularLimit.y); this.setLimit(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z, this._angularZMotion, this._minAngularLimit.z, this._maxAngularLimit.z); this.setSpring(ConfigurableConstraint.MOTION_LINEAR_INDEX_X, this._linearLimitSpring.x); this.setSpring(ConfigurableConstraint.MOTION_LINEAR_INDEX_Y, this._linearLimitSpring.y); this.setSpring(ConfigurableConstraint.MOTION_LINEAR_INDEX_Z, this._linearLimitSpring.z); this.setSpring(ConfigurableConstraint.MOTION_ANGULAR_INDEX_X, this._angularLimitSpring.x); this.setSpring(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y, this._angularLimitSpring.y); this.setSpring(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z, this._angularLimitSpring.z); this.setBounce(ConfigurableConstraint.MOTION_LINEAR_INDEX_X, this._linearBounce.x); this.setBounce(ConfigurableConstraint.MOTION_LINEAR_INDEX_Y, this._linearBounce.y); this.setBounce(ConfigurableConstraint.MOTION_LINEAR_INDEX_Z, this._linearBounce.z); this.setBounce(ConfigurableConstraint.MOTION_ANGULAR_INDEX_X, this._angularBounce.x); this.setBounce(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y, this._angularBounce.y); this.setBounce(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z, this._angularBounce.z); this.setDamping(ConfigurableConstraint.MOTION_LINEAR_INDEX_X, this._linearDamp.x); this.setDamping(ConfigurableConstraint.MOTION_LINEAR_INDEX_Y, this._linearDamp.y); this.setDamping(ConfigurableConstraint.MOTION_LINEAR_INDEX_Z, this._linearDamp.z); this.setDamping(ConfigurableConstraint.MOTION_ANGULAR_INDEX_X, this._angularDamp.x); this.setDamping(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y, this._angularDamp.y); this.setDamping(ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z, this._angularDamp.z); this.setFrames(); this.setEquilibriumPoint(0, 0); } _onAdded() { super._onAdded(); } _onEnable() { if (!this._btConstraint) return; super._onEnable(); if (this._btConstraint) Physics3D._bullet.btTypedConstraint_setEnabled(this._btConstraint, true); } _onDisable() { super._onDisable(); if (!this.connectedBody) this._removeFromSimulation(); if (this._btConstraint) Physics3D._bullet.btTypedConstraint_setEnabled(this._btConstraint, false); } _parse(data, interactMap = null) { super._parse(data); this._axis.fromArray(data.axis); this._secondaryAxis.fromArray(data.secondaryAxis); var limitlimit = data.linearLimit; this._minLinearLimit.setValue(-limitlimit, -limitlimit, -limitlimit); this._maxLinearLimit.setValue(limitlimit, limitlimit, limitlimit); var limitSpring = data.linearLimitSpring; this._linearLimitSpring.setValue(limitSpring, limitSpring, limitSpring); var limitDamp = data.linearLimitDamper; this._linearDamp.setValue(limitDamp, limitDamp, limitDamp); var limitBounciness = data.linearLimitBounciness; this._linearBounce.setValue(limitBounciness, limitBounciness, limitBounciness); var xlowAngularLimit = data.lowAngularXLimit; var xhighAngularLimit = data.highAngularXLimit; var yAngularLimit = data.angularYLimit; var zAngularLimit = data.angularZLimit; this._minAngularLimit.setValue(xlowAngularLimit, -yAngularLimit, -zAngularLimit); this._maxAngularLimit.setValue(xhighAngularLimit, yAngularLimit, zAngularLimit); var xhighAngularBounciness = data.highAngularXLimitBounciness; var ybounciness = data.angularYLimitBounciness; var zbounciness = data.angularZLimitBounciness; this._angularBounce.setValue(xhighAngularBounciness, ybounciness, zbounciness); var xAngularSpring = data.angularXLimitSpring; var yzAngularSpriny = data.angularYZLimitSpring; this._angularLimitSpring.setValue(xAngularSpring, yzAngularSpriny, yzAngularSpriny); var xAngularDamper = data.angularXLimitDamper; var yzAngularDamper = data.angularYZLimitDamper; this._angularDamp.setValue(xAngularDamper, yzAngularDamper, yzAngularDamper); this.XMotion = data.xMotion; this.YMotion = data.yMotion; this.ZMotion = data.zMotion; this.angularXMotion = data.angularXMotion; this.angularYMotion = data.angularYMotion; this.angularZMotion = data.angularZMotion; if (data.rigidbodyID != -1 && data.connectRigidbodyID != -1) { interactMap.component.push(this); interactMap.data.push(data); } (data.breakForce != undefined) && (this.breakForce = data.breakForce); (data.breakTorque != undefined) && (this.breakTorque = data.breakTorque); } _parseInteractive(data = null, spriteMap = null) { var rigidBodySprite = spriteMap[data.rigidbodyID]; var rigidBody = rigidBodySprite.getComponent(Rigidbody3D); var connectSprite = spriteMap[data.connectRigidbodyID]; var connectRigidbody = connectSprite.getComponent(Rigidbody3D); this.ownBody = rigidBody; this.connectedBody = connectRigidbody; } _onDestroy() { super._onDestroy(); } _cloneTo(dest) { } } ConfigurableConstraint.CONFIG_MOTION_TYPE_LOCKED = 0; ConfigurableConstraint.CONFIG_MOTION_TYPE_LIMITED = 1; ConfigurableConstraint.CONFIG_MOTION_TYPE_FREE = 2; ConfigurableConstraint.MOTION_LINEAR_INDEX_X = 0; ConfigurableConstraint.MOTION_LINEAR_INDEX_Y = 1; ConfigurableConstraint.MOTION_LINEAR_INDEX_Z = 2; ConfigurableConstraint.MOTION_ANGULAR_INDEX_X = 3; ConfigurableConstraint.MOTION_ANGULAR_INDEX_Y = 4; ConfigurableConstraint.MOTION_ANGULAR_INDEX_Z = 5; ConfigurableConstraint.RO_XYZ = 0; ConfigurableConstraint.RO_XZY = 1; ConfigurableConstraint.RO_YXZ = 2; ConfigurableConstraint.RO_YZX = 3; ConfigurableConstraint.RO_ZXY = 4; ConfigurableConstraint.RO_ZYX = 5; class Laya3D { constructor() { } static get enablePhysics() { return Physics3D._enablePhysics; } static _cancelLoadByUrl(url) { Laya.Laya.loader.cancelLoadByUrl(url); Laya3D._innerFirstLevelLoaderManager.cancelLoadByUrl(url); Laya3D._innerSecondLevelLoaderManager.cancelLoadByUrl(url); Laya3D._innerThirdLevelLoaderManager.cancelLoadByUrl(url); Laya3D._innerFourthLevelLoaderManager.cancelLoadByUrl(url); } static _changeWebGLSize(width, height) { Laya.WebGL.onStageResize(width, height); RenderContext3D.clientWidth = width; RenderContext3D.clientHeight = height; } static __init__(width, height, config) { Laya.Config.isAntialias = config.isAntialias; Laya.Config.isAlpha = config.isAlpha; Laya.Config.premultipliedAlpha = config.premultipliedAlpha; Laya.Config.isStencil = config.isStencil; if (!Laya.WebGL.enable()) { alert("Laya3D init error,must support webGL!"); return; } Laya.RunDriver.changeWebGLSize = Laya3D._changeWebGLSize; Laya.Render.is3DMode = true; Laya.Laya.init(width, height); if (!Laya.Render.supportWebGLPlusRendering) { Laya.LayaGL.instance = Laya.WebGLContext.mainContext; Laya.LayaGL.instance.createCommandEncoder = function (reserveSize = 128, adjustSize = 64, isSyncToRenderThread = false) { return new Laya.CommandEncoder(this, reserveSize, adjustSize, isSyncToRenderThread); }; } config._multiLighting = config.enableMultiLight && Laya.SystemUtils.supportTextureFormat(Laya.TextureFormat.R32G32B32A32); ILaya3D.Shader3D = Shader3D; ILaya3D.Scene3D = Scene3D; ILaya3D.MeshRenderStaticBatchManager = MeshRenderStaticBatchManager; ILaya3D.MeshRenderDynamicBatchManager = MeshRenderDynamicBatchManager; ILaya3D.SubMeshDynamicBatch = SubMeshDynamicBatch; ILaya3D.Laya3D = Laya3D; ILaya3D.Matrix4x4 = Matrix4x4; ILaya3D.Physics3D = Physics3D; ILaya3D.ShadowLightType = exports.ShadowLightType; Laya3D.enableNative3D(); if (config.isUseCannonPhysicsEngine) Physics3D.__cannoninit__(); Physics3D.__bulletinit__(); VertexElementFormat.__init__(); VertexMesh.__init__(); VertexShurikenParticleBillboard.__init__(); VertexShurikenParticleMesh.__init__(); VertexPositionTexture0.__init__(); VertexTrail.__init__(); VertexPositionTerrain.__init__(); PixelLineVertex.__init__(); SubMeshInstanceBatch.__init__(); SubMeshDynamicBatch.__init__(); ShaderInit3D.__init__(); ShadowUtils.init(); PBRMaterial.__init__(); PBRStandardMaterial.__init__(); PBRSpecularMaterial.__init__(); SkyPanoramicMaterial.__init__(); Mesh.__init__(); PrimitiveMesh.__init__(); Sprite3D.__init__(); RenderableSprite3D.__init__(); MeshSprite3D.__init__(); SkinnedMeshSprite3D.__init__(); ShuriKenParticle3D.__init__(); TrailSprite3D.__init__(); PostProcess.__init__(); Scene3D.__init__(); MeshRenderStaticBatchManager.__init__(); Material.__initDefine__(); BaseMaterial.__initDefine__(); BlinnPhongMaterial.__initDefine__(); SkyProceduralMaterial.__initDefine__(); UnlitMaterial.__initDefine__(); TrailMaterial.__initDefine__(); EffectMaterial.__initDefine__(); WaterPrimaryMaterial.__initDefine__(); ShurikenParticleMaterial.__initDefine__(); ExtendTerrainMaterial.__initDefine__(); PixelLineMaterial.__initDefine__(); SkyBoxMaterial.__initDefine__(); Command.__init__(); Laya.ClassUtils.regClass("Laya.SkyPanoramicMaterial", SkyPanoramicMaterial); Laya.ClassUtils.regClass("Laya.EffectMaterial", EffectMaterial); Laya.ClassUtils.regClass("Laya.UnlitMaterial", UnlitMaterial); Laya.ClassUtils.regClass("Laya.BlinnPhongMaterial", BlinnPhongMaterial); Laya.ClassUtils.regClass("Laya.SkyProceduralMaterial", SkyProceduralMaterial); Laya.ClassUtils.regClass("Laya.PBRStandardMaterial", PBRStandardMaterial); Laya.ClassUtils.regClass("Laya.PBRSpecularMaterial", PBRSpecularMaterial); Laya.ClassUtils.regClass("Laya.SkyBoxMaterial", SkyBoxMaterial); Laya.ClassUtils.regClass("Laya.WaterPrimaryMaterial", WaterPrimaryMaterial); Laya.ClassUtils.regClass("Laya.ExtendTerrainMaterial", ExtendTerrainMaterial); Laya.ClassUtils.regClass("Laya.ShurikenParticleMaterial", ShurikenParticleMaterial); Laya.ClassUtils.regClass("Laya.TrailMaterial", TrailMaterial); Laya.ClassUtils.regClass("Laya.PhysicsCollider", PhysicsCollider); Laya.ClassUtils.regClass("Laya.Rigidbody3D", Rigidbody3D); Laya.ClassUtils.regClass("Laya.CharacterController", CharacterController); Laya.ClassUtils.regClass("Laya.Animator", Animator); Laya.ClassUtils.regClass("PhysicsCollider", PhysicsCollider); Laya.ClassUtils.regClass("CharacterController", CharacterController); Laya.ClassUtils.regClass("Animator", Animator); Laya.ClassUtils.regClass("Rigidbody3D", Rigidbody3D); Laya.ClassUtils.regClass("FixedConstraint", FixedConstraint); Laya.ClassUtils.regClass("ConfigurableConstraint", ConfigurableConstraint); PixelLineMaterial.defaultMaterial = new PixelLineMaterial(); BlinnPhongMaterial.defaultMaterial = new BlinnPhongMaterial(); EffectMaterial.defaultMaterial = new EffectMaterial(); UnlitMaterial.defaultMaterial = new UnlitMaterial(); ShurikenParticleMaterial.defaultMaterial = new ShurikenParticleMaterial(); TrailMaterial.defaultMaterial = new TrailMaterial(); SkyProceduralMaterial.defaultMaterial = new SkyProceduralMaterial(); SkyBoxMaterial.defaultMaterial = new SkyBoxMaterial(); WaterPrimaryMaterial.defaultMaterial = new WaterPrimaryMaterial(); PixelLineMaterial.defaultMaterial.lock = true; BlinnPhongMaterial.defaultMaterial.lock = true; EffectMaterial.defaultMaterial.lock = true; UnlitMaterial.defaultMaterial.lock = true; ShurikenParticleMaterial.defaultMaterial.lock = true; TrailMaterial.defaultMaterial.lock = true; SkyProceduralMaterial.defaultMaterial.lock = true; SkyBoxMaterial.defaultMaterial.lock = true; WaterPrimaryMaterial.defaultMaterial.lock = true; Laya.Texture2D.__init__(); TextureCube.__init__(); SkyBox.__init__(); SkyDome.__init__(); ScreenQuad.__init__(); ScreenTriangle.__init__(); FrustumCulling.__init__(); HalfFloatUtils.__init__(); var createMap = Laya.LoaderManager.createMap; createMap["lh"] = [Laya3D.HIERARCHY, Scene3DUtils._parse]; createMap["ls"] = [Laya3D.HIERARCHY, Scene3DUtils._parseScene]; createMap["lm"] = [Laya3D.MESH, MeshReader._parse]; createMap["lmat"] = [Laya3D.MATERIAL, Material._parse]; createMap["jpg"] = [Laya3D.TEXTURE2D, Laya.Texture2D._parse]; createMap["jpeg"] = [Laya3D.TEXTURE2D, Laya.Texture2D._parse]; createMap["bmp"] = [Laya3D.TEXTURE2D, Laya.Texture2D._parse]; createMap["gif"] = [Laya3D.TEXTURE2D, Laya.Texture2D._parse]; createMap["png"] = [Laya3D.TEXTURE2D, Laya.Texture2D._parse]; createMap["dds"] = [Laya3D.TEXTURE2D, Laya.Texture2D._parse]; createMap["ktx"] = [Laya3D.TEXTURE2D, Laya.Texture2D._parse]; createMap["pvr"] = [Laya3D.TEXTURE2D, Laya.Texture2D._parse]; createMap["lani"] = [Laya3D.ANIMATIONCLIP, AnimationClip._parse]; createMap["lav"] = [Laya3D.AVATAR, Avatar._parse]; createMap["ltc"] = [Laya3D.TEXTURECUBE, TextureCube._parse]; createMap["ltcb"] = [Laya3D.TEXTURECUBEBIN, TextureCube._parseBin]; createMap["ltcb.ls"] = [Laya3D.TEXTURECUBEBIN, TextureCube._parseBin]; var parserMap = Laya.Loader.parserMap; parserMap[Laya3D.HIERARCHY] = Laya3D._loadHierarchy; parserMap[Laya3D.MESH] = Laya3D._loadMesh; parserMap[Laya3D.MATERIAL] = Laya3D._loadMaterial; parserMap[Laya3D.TEXTURECUBE] = Laya3D._loadTextureCube; parserMap[Laya3D.TEXTURECUBEBIN] = Laya3D._loadTextureCubeBin; parserMap[Laya3D.TEXTURE2D] = Laya3D._loadTexture2D; parserMap[Laya3D.ANIMATIONCLIP] = Laya3D._loadAnimationClip; parserMap[Laya3D.AVATAR] = Laya3D._loadAvatar; Laya3D._innerFirstLevelLoaderManager.on(Laya.Event.ERROR, null, Laya3D._eventLoadManagerError); Laya3D._innerSecondLevelLoaderManager.on(Laya.Event.ERROR, null, Laya3D._eventLoadManagerError); Laya3D._innerThirdLevelLoaderManager.on(Laya.Event.ERROR, null, Laya3D._eventLoadManagerError); Laya3D._innerFourthLevelLoaderManager.on(Laya.Event.ERROR, null, Laya3D._eventLoadManagerError); } static enableNative3D() { var shaderData = ShaderData; var shader3D = ShaderInstance; var skinnedMeshRender = SkinnedMeshRenderer; var avatar = Avatar; var frustumCulling = FrustumCulling; if (Laya.Render.supportWebGLPlusRendering) { shaderData.prototype._initData = shaderData.prototype._initDataForNative; shaderData.prototype.setBool = shaderData.prototype.setBoolForNative; shaderData.prototype.getBool = shaderData.prototype.getBoolForNative; shaderData.prototype.setInt = shaderData.prototype.setIntForNative; shaderData.prototype.getInt = shaderData.prototype.getIntForNative; shaderData.prototype.setNumber = shaderData.prototype.setNumberForNative; shaderData.prototype.getNumber = shaderData.prototype.getNumberForNative; shaderData.prototype.setVector = shaderData.prototype.setVectorForNative; shaderData.prototype.getVector = shaderData.prototype.getVectorForNative; shaderData.prototype.setVector2 = shaderData.prototype.setVector2ForNative; shaderData.prototype.getVector2 = shaderData.prototype.getVector2ForNative; shaderData.prototype.setVector3 = shaderData.prototype.setVector3ForNative; shaderData.prototype.getVector3 = shaderData.prototype.getVector3ForNative; shaderData.prototype.setQuaternion = shaderData.prototype.setQuaternionForNative; shaderData.prototype.getQuaternion = shaderData.prototype.getQuaternionForNative; shaderData.prototype.setMatrix4x4 = shaderData.prototype.setMatrix4x4ForNative; shaderData.prototype.getMatrix4x4 = shaderData.prototype.getMatrix4x4ForNative; shaderData.prototype.setBuffer = shaderData.prototype.setBufferForNative; shaderData.prototype.getBuffer = shaderData.prototype.getBufferForNative; shaderData.prototype.setTexture = shaderData.prototype.setTextureForNative; shaderData.prototype.getTexture = shaderData.prototype.getTextureForNative; shaderData.prototype.setAttribute = shaderData.prototype.setAttributeForNative; shaderData.prototype.getAttribute = shaderData.prototype.getAttributeForNative; shaderData.prototype.cloneTo = shaderData.prototype.cloneToForNative; shaderData.prototype.getData = shaderData.prototype.getDataForNative; shader3D.prototype._uniformMatrix2fv = shader3D.prototype._uniformMatrix2fvForNative; shader3D.prototype._uniformMatrix3fv = shader3D.prototype._uniformMatrix3fvForNative; shader3D.prototype._uniformMatrix4fv = shader3D.prototype._uniformMatrix4fvForNative; Laya.LayaGLRunner.uploadShaderUniforms = Laya.LayaGLRunner.uploadShaderUniformsForNative; } if (Laya.Render.supportWebGLPlusCulling) { frustumCulling.renderObjectCulling = FrustumCulling.renderObjectCullingNative; } if (Laya.Render.supportWebGLPlusAnimation) { avatar.prototype._cloneDatasToAnimator = avatar.prototype._cloneDatasToAnimatorNative; var animationClip = AnimationClip; animationClip.prototype._evaluateClipDatasRealTime = animationClip.prototype._evaluateClipDatasRealTimeForNative; skinnedMeshRender.prototype._computeSkinnedData = skinnedMeshRender.prototype._computeSkinnedDataForNative; } } static formatRelativePath(base, value) { var path; path = base + value; var char1 = value.charAt(0); if (char1 === ".") { var parts = path.split("/"); for (var i = 0, len = parts.length; i < len; i++) { if (parts[i] == '..') { var index = i - 1; if (index > 0 && parts[index] !== '..') { parts.splice(index, 2); i -= 2; } } } path = parts.join('/'); } return path; } static _endLoad(loader, content = null, subResous = null) { if (subResous) { for (var i = 0, n = subResous.length; i < n; i++) { var resou = Laya.Loader.getRes(subResous[i]); (resou) && (resou._removeReference()); } } loader.endLoad(content); } static _eventLoadManagerError(msg) { Laya.Laya.loader.event(Laya.Event.ERROR, msg); } static _addHierarchyInnerUrls(urls, urlMap, urlVersion, hierarchyBasePath, path, type, constructParams = null, propertyParams = null) { var formatUrl = Laya3D.formatRelativePath(hierarchyBasePath, path); (urlVersion) && (formatUrl = formatUrl + urlVersion); urls.push({ url: formatUrl, type: type, constructParams: constructParams, propertyParams: propertyParams }); urlMap.push(formatUrl); return formatUrl; } static _getSprite3DHierarchyInnerUrls(node, firstLevelUrls, secondLevelUrls, thirdLevelUrls, fourthLelUrls, subUrls, urlVersion, hierarchyBasePath) { var i, n; var props = node.props; switch (node.type) { case "Scene3D": var lightmaps = props.lightmaps; for (i = 0, n = lightmaps.length; i < n; i++) { var lightMap = lightmaps[i]; if (lightMap.path) { lightMap.path = Laya3D._addHierarchyInnerUrls(fourthLelUrls, subUrls, urlVersion, hierarchyBasePath, lightMap.path, Laya3D.TEXTURE2D, lightMap.constructParams, lightMap.propertyParams); } else { var lightmapColorData = lightMap.color; lightmapColorData.path = Laya3D._addHierarchyInnerUrls(fourthLelUrls, subUrls, urlVersion, hierarchyBasePath, lightmapColorData.path, Laya3D.TEXTURE2D, lightmapColorData.constructParams, lightmapColorData.propertyParams); var lightmapDirectionData = lightMap.direction; if (lightmapDirectionData) lightmapDirectionData.path = Laya3D._addHierarchyInnerUrls(fourthLelUrls, subUrls, urlVersion, hierarchyBasePath, lightmapDirectionData.path, Laya3D.TEXTURE2D, lightmapDirectionData.constructParams, lightmapDirectionData.propertyParams); } } var reflectionTextureData = props.reflectionTexture; (reflectionTextureData) && (props.reflection = Laya3D._addHierarchyInnerUrls(thirdLevelUrls, subUrls, urlVersion, hierarchyBasePath, reflectionTextureData, Laya3D.TEXTURECUBE)); var reflectionData = props.reflection; (reflectionData) && (props.reflection = Laya3D._addHierarchyInnerUrls(fourthLelUrls, subUrls, urlVersion, hierarchyBasePath, reflectionData, Laya3D.TEXTURECUBEBIN)); if (props.sky) { var skyboxMaterial = props.sky.material; (skyboxMaterial) && (skyboxMaterial.path = Laya3D._addHierarchyInnerUrls(secondLevelUrls, subUrls, urlVersion, hierarchyBasePath, skyboxMaterial.path, Laya3D.MATERIAL)); } break; case "Camera": var skyboxMatData = props.skyboxMaterial; (skyboxMatData) && (skyboxMatData.path = Laya3D._addHierarchyInnerUrls(secondLevelUrls, subUrls, urlVersion, hierarchyBasePath, skyboxMatData.path, Laya3D.MATERIAL)); break; case "TrailSprite3D": case "MeshSprite3D": case "SkinnedMeshSprite3D": var meshPath = props.meshPath; (meshPath) && (props.meshPath = Laya3D._addHierarchyInnerUrls(firstLevelUrls, subUrls, urlVersion, hierarchyBasePath, meshPath, Laya3D.MESH)); var materials = props.materials; if (materials) for (i = 0, n = materials.length; i < n; i++) materials[i].path = Laya3D._addHierarchyInnerUrls(secondLevelUrls, subUrls, urlVersion, hierarchyBasePath, materials[i].path, Laya3D.MATERIAL); break; case "ShuriKenParticle3D": if (props.main) { var resources = props.renderer.resources; var mesh = resources.mesh; var material = resources.material; (mesh) && (resources.mesh = Laya3D._addHierarchyInnerUrls(firstLevelUrls, subUrls, urlVersion, hierarchyBasePath, mesh, Laya3D.MESH)); (material) && (resources.material = Laya3D._addHierarchyInnerUrls(secondLevelUrls, subUrls, urlVersion, hierarchyBasePath, material, Laya3D.MATERIAL)); } else { var parMeshPath = props.meshPath; (parMeshPath) && (props.meshPath = Laya3D._addHierarchyInnerUrls(firstLevelUrls, subUrls, urlVersion, hierarchyBasePath, parMeshPath, Laya3D.MESH)); props.material.path = Laya3D._addHierarchyInnerUrls(secondLevelUrls, subUrls, urlVersion, hierarchyBasePath, props.material.path, Laya3D.MATERIAL); } break; case "Terrain": Laya3D._addHierarchyInnerUrls(fourthLelUrls, subUrls, urlVersion, hierarchyBasePath, props.dataPath, Laya3D.TERRAINRES); break; } var components = node.components; if (components) { for (var k = 0, p = components.length; k < p; k++) { var component = components[k]; switch (component.type) { case "Animator": var avatarPath = component.avatarPath; var avatarData = component.avatar; (avatarData) && (avatarData.path = Laya3D._addHierarchyInnerUrls(fourthLelUrls, subUrls, urlVersion, hierarchyBasePath, avatarData.path, Laya3D.AVATAR)); var clipPaths = component.clipPaths; if (!clipPaths) { var layersData = component.layers; for (i = 0; i < layersData.length; i++) { var states = layersData[i].states; for (var j = 0, m = states.length; j < m; j++) { var clipPath = states[j].clipPath; (clipPath) && (states[j].clipPath = Laya3D._addHierarchyInnerUrls(fourthLelUrls, subUrls, urlVersion, hierarchyBasePath, clipPath, Laya3D.ANIMATIONCLIP)); } } } else { for (i = 0, n = clipPaths.length; i < n; i++) clipPaths[i] = Laya3D._addHierarchyInnerUrls(fourthLelUrls, subUrls, urlVersion, hierarchyBasePath, clipPaths[i], Laya3D.ANIMATIONCLIP); } break; case "PhysicsCollider": case "Rigidbody3D": case "CharacterController": var shapes = component.shapes; for (i = 0; i < shapes.length; i++) { var shape = shapes[i]; if (shape.type === "MeshColliderShape") { var mesh = shape.mesh; (mesh) && (shape.mesh = Laya3D._addHierarchyInnerUrls(firstLevelUrls, subUrls, urlVersion, hierarchyBasePath, mesh, Laya3D.MESH)); } } break; } } } var children = node.child; for (i = 0, n = children.length; i < n; i++) Laya3D._getSprite3DHierarchyInnerUrls(children[i], firstLevelUrls, secondLevelUrls, thirdLevelUrls, fourthLelUrls, subUrls, urlVersion, hierarchyBasePath); } static _loadHierarchy(loader) { loader._originType = loader.type; loader.on(Laya.Event.LOADED, null, Laya3D._onHierarchylhLoaded, [loader]); loader.load(loader.url, Laya.Loader.JSON, false, null, true); } static _onHierarchylhLoaded(loader, lhData) { var url = loader.url; var urlVersion = Utils3D.getURLVerion(url); var hierarchyBasePath = Laya.URL.getPath(url); var firstLevUrls = []; var secondLevUrls = []; var thirdLevUrls = []; var forthLevUrls = []; var subUrls = []; Laya3D._getSprite3DHierarchyInnerUrls(lhData.data, firstLevUrls, secondLevUrls, thirdLevUrls, forthLevUrls, subUrls, urlVersion, hierarchyBasePath); var urlCount = firstLevUrls.length + secondLevUrls.length + forthLevUrls.length; var totalProcessCount = urlCount + 1; var weight = 1 / totalProcessCount; Laya3D._onProcessChange(loader, 0, weight, 1.0); if (forthLevUrls.length > 0) { var processCeil = urlCount / totalProcessCount; var processHandler = Laya.Handler.create(null, Laya3D._onProcessChange, [loader, weight, processCeil], false); Laya3D._innerFourthLevelLoaderManager._create(forthLevUrls, false, Laya.Handler.create(null, Laya3D._onHierarchyInnerForthLevResouLoaded, [loader, processHandler, lhData, subUrls, firstLevUrls, secondLevUrls, thirdLevUrls, weight + processCeil * forthLevUrls.length, processCeil]), processHandler, null, null, null, 1, true); } else { Laya3D._onHierarchyInnerForthLevResouLoaded(loader, null, lhData, subUrls, firstLevUrls, secondLevUrls, thirdLevUrls, weight, processCeil); } } static _onHierarchyInnerForthLevResouLoaded(loader, processHandler, lhData, subUrls, firstLevUrls, secondLevUrls, thirdLevUrls, processOffset, processCeil) { (processHandler) && (processHandler.recover()); if (thirdLevUrls.length > 0) { var process = Laya.Handler.create(null, Laya3D._onProcessChange, [loader, processOffset, processCeil], false); Laya3D._innerThirdLevelLoaderManager._create(thirdLevUrls, false, Laya.Handler.create(null, Laya3D._onHierarchyInnerThirdLevResouLoaded, [loader, process, lhData, subUrls, firstLevUrls, secondLevUrls, processOffset + processCeil * secondLevUrls.length, processCeil]), processHandler, null, null, null, 1, true); } else { Laya3D._onHierarchyInnerThirdLevResouLoaded(loader, null, lhData, subUrls, firstLevUrls, secondLevUrls, processOffset, processCeil); } } static _onHierarchyInnerThirdLevResouLoaded(loader, processHandler, lhData, subUrls, firstLevUrls, secondLevUrls, processOffset, processCeil) { (processHandler) && (processHandler.recover()); if (secondLevUrls.length > 0) { var process = Laya.Handler.create(null, Laya3D._onProcessChange, [loader, processOffset, processCeil], false); Laya3D._innerSecondLevelLoaderManager._create(secondLevUrls, false, Laya.Handler.create(null, Laya3D._onHierarchyInnerSecondLevResouLoaded, [loader, process, lhData, subUrls, firstLevUrls, processOffset + processCeil * secondLevUrls.length, processCeil]), processHandler, null, null, null, 1, true); } else { Laya3D._onHierarchyInnerSecondLevResouLoaded(loader, null, lhData, subUrls, firstLevUrls, processOffset, processCeil); } } static _onHierarchyInnerSecondLevResouLoaded(loader, processHandler, lhData, subUrls, firstLevUrls, processOffset, processCeil) { (processHandler) && (processHandler.recover()); if (firstLevUrls.length > 0) { var process = Laya.Handler.create(null, Laya3D._onProcessChange, [loader, processOffset, processCeil], false); Laya3D._innerFirstLevelLoaderManager._create(firstLevUrls, false, Laya.Handler.create(null, Laya3D._onHierarchyInnerFirstLevResouLoaded, [loader, process, lhData, subUrls]), processHandler, null, null, null, 1, true); } else { Laya3D._onHierarchyInnerFirstLevResouLoaded(loader, null, lhData, subUrls); } } static _onHierarchyInnerFirstLevResouLoaded(loader, processHandler, lhData, subUrls) { (processHandler) && (processHandler.recover()); loader._cache = loader._createCache; var item = lhData.data.type === "Scene3D" ? Scene3DUtils._parseScene(lhData, loader._propertyParams, loader._constructParams) : Scene3DUtils._parse(lhData, loader._propertyParams, loader._constructParams); Laya3D._endLoad(loader, item, subUrls); } static _loadMesh(loader) { loader.on(Laya.Event.LOADED, null, Laya3D._onMeshLmLoaded, [loader]); loader.load(loader.url, Laya.Loader.BUFFER, false, null, true); } static _onMeshLmLoaded(loader, lmData) { loader._cache = loader._createCache; var mesh = MeshReader._parse(lmData, loader._propertyParams, loader._constructParams); Laya3D._endLoad(loader, mesh); } static _loadMaterial(loader) { loader.on(Laya.Event.LOADED, null, Laya3D._onMaterilLmatLoaded, [loader]); loader.load(loader.url, Laya.Loader.JSON, false, null, true); } static _onMaterilLmatLoaded(loader, lmatData) { var url = loader.url; var urlVersion = Utils3D.getURLVerion(url); var materialBasePath = Laya.URL.getPath(url); var urls = []; var subUrls = []; var customProps = lmatData.customProps; var formatSubUrl; var version = lmatData.version; switch (version) { case "LAYAMATERIAL:01": case "LAYAMATERIAL:02": var i, n; var textures = lmatData.props.textures; if (textures) { for (i = 0, n = textures.length; i < n; i++) { var tex2D = textures[i]; var tex2DPath = tex2D.path; if (tex2DPath) { formatSubUrl = Laya3D.formatRelativePath(materialBasePath, tex2DPath); (urlVersion) && (formatSubUrl = formatSubUrl + urlVersion); urls.push({ url: formatSubUrl, constructParams: tex2D.constructParams, propertyParams: tex2D.propertyParams }); subUrls.push(formatSubUrl); tex2D.path = formatSubUrl; } } } break; default: throw new Error("Laya3D:unkonwn version."); } var urlCount = urls.length; var totalProcessCount = urlCount + 1; var lmatWeight = 1 / totalProcessCount; Laya3D._onProcessChange(loader, 0, lmatWeight, 1.0); if (urlCount > 0) { var processHandler = Laya.Handler.create(null, Laya3D._onProcessChange, [loader, lmatWeight, urlCount / totalProcessCount], false); Laya3D._innerFourthLevelLoaderManager._create(urls, false, Laya.Handler.create(null, Laya3D._onMateialTexturesLoaded, [loader, processHandler, lmatData, subUrls]), processHandler, null, null, null, 1, true); } else { Laya3D._onMateialTexturesLoaded(loader, null, lmatData, null); } } static _onMateialTexturesLoaded(loader, processHandler, lmatData, subUrls) { loader._cache = loader._createCache; var mat = Material._parse(lmatData, loader._propertyParams, loader._constructParams); Laya3D._endLoad(loader, mat, subUrls); (processHandler) && (processHandler.recover()); } static _loadAvatar(loader) { loader.on(Laya.Event.LOADED, null, function (data) { loader._cache = loader._createCache; var avatar = Avatar._parse(data, loader._propertyParams, loader._constructParams); Laya3D._endLoad(loader, avatar); }); loader.load(loader.url, Laya.Loader.JSON, false, null, true); } static _loadAnimationClip(loader) { loader.on(Laya.Event.LOADED, null, function (data) { loader._cache = loader._createCache; var clip = AnimationClip._parse(data, loader._propertyParams, loader._constructParams); Laya3D._endLoad(loader, clip); }); loader.load(loader.url, Laya.Loader.BUFFER, false, null, true); } static _loadTexture2D(loader) { var url = loader.url; var index = url.lastIndexOf('.') + 1; var verIndex = url.indexOf('?'); var endIndex = verIndex == -1 ? url.length : verIndex; var ext = url.substr(index, endIndex - index); var type; switch (ext) { case "jpg": case "jpeg": case "bmp": case "gif": case "png": type = "nativeimage"; break; case "dds": case "ktx": case "pvr": type = Laya.Loader.BUFFER; break; } loader.on(Laya.Event.LOADED, null, function (image) { loader._cache = loader._createCache; var tex = Laya.Texture2D._parse(image, loader._propertyParams, loader._constructParams); Laya3D._endLoad(loader, tex); }); loader.load(loader.url, type, false, null, true); } static _loadTextureCube(loader) { loader.on(Laya.Event.LOADED, null, Laya3D._onTextureCubeLtcLoaded, [loader]); loader.load(loader.url, Laya.Loader.JSON, false, null, true); } static _loadTextureCubeBin(loader) { loader.on(Laya.Event.LOADED, null, (data) => { loader._cache = loader._createCache; var byte = new Laya.Byte(data); var version = byte.readUTFString(); if (version !== "LAYATEXTURECUBE:0000") throw "Laya3D:unknow version."; var format = byte.readUint8(); var mipCount = byte.getUint8(); var size = byte.readUint16(); var filterMode = byte.getUint8(); var warpModeU = byte.getUint8(); var warpModev = byte.getUint8(); var anisoLevel = byte.getUint8(); var cubemap = new TextureCube(size, format, mipCount > 1 ? true : false); cubemap.filterMode = filterMode; cubemap.wrapModeU = warpModeU; cubemap.wrapModeV = warpModev; cubemap.anisoLevel = anisoLevel; var pos = byte.pos; var mipSize = size; for (var i = 0; i < mipCount; i++) { var uint8Arrays = new Array(6); var mipPixelLength = mipSize * mipSize * cubemap._getFormatByteCount(); for (var j = 0; j < 6; j++) { uint8Arrays[j] = new Uint8Array(data, pos, mipPixelLength); pos += mipPixelLength; } cubemap.setSixSidePixels(uint8Arrays, i); mipSize /= 2; } Laya3D._endLoad(loader, cubemap); }); loader.load(loader.url, Laya.Loader.BUFFER, false, null, true); } static _onTextureCubeLtcLoaded(loader, ltcData) { var ltcBasePath = Laya.URL.getPath(loader.url); var urls = [Laya3D.formatRelativePath(ltcBasePath, ltcData.front), Laya3D.formatRelativePath(ltcBasePath, ltcData.back), Laya3D.formatRelativePath(ltcBasePath, ltcData.left), Laya3D.formatRelativePath(ltcBasePath, ltcData.right), Laya3D.formatRelativePath(ltcBasePath, ltcData.up), Laya3D.formatRelativePath(ltcBasePath, ltcData.down)]; var ltcWeight = 1.0 / 7.0; Laya3D._onProcessChange(loader, 0, ltcWeight, 1.0); var processHandler = Laya.Handler.create(null, Laya3D._onProcessChange, [loader, ltcWeight, 6 / 7], false); Laya3D._innerFourthLevelLoaderManager.load(urls, Laya.Handler.create(null, Laya3D._onTextureCubeImagesLoaded, [loader, urls, processHandler]), processHandler, "nativeimage"); } static _onTextureCubeImagesLoaded(loader, urls, processHandler) { var images = new Array(6); for (var i = 0; i < 6; i++) images[i] = Laya.Loader.getRes(urls[i]); loader._cache = loader._createCache; var tex = TextureCube._parse(images, loader._propertyParams, loader._constructParams); processHandler.recover(); for (i = 0; i < 6; i++) Laya.Loader.clearRes(urls[i]); Laya3D._endLoad(loader, tex); } static _onProcessChange(loader, offset, weight, process) { process = offset + process * weight; (process < 1.0) && (loader.event(Laya.Event.PROGRESS, process * 2 / 3 + 1 / 3)); } static init(width, height, config = null, compolete = null) { if (Laya3D._isInit) { compolete && compolete.run(); return; } Laya3D._isInit = true; (config) && (config.cloneTo(Config3D._config)); config = Config3D._config; FrustumCulling.debugFrustumCulling = config.debugFrustumCulling; Laya3D._editerEnvironment = config._editerEnvironment; Scene3D.octreeCulling = config.octreeCulling; Scene3D.octreeInitialSize = config.octreeInitialSize; Scene3D.octreeInitialCenter = config.octreeInitialCenter; Scene3D.octreeMinNodeSize = config.octreeMinNodeSize; Scene3D.octreeLooseness = config.octreeLooseness; var physics3D = window.Physics3D; if (physics3D == null || config.isUseCannonPhysicsEngine) { Physics3D._enablePhysics = false; Laya3D.__init__(width, height, config); compolete && compolete.run(); } else { Physics3D._enablePhysics = true; physics3D(config.defaultPhysicsMemory * 16, BulletInteractive._interactive).then(function () { Laya3D.__init__(width, height, config); compolete && compolete.run(); }); } } } Laya3D.HIERARCHY = "HIERARCHY"; Laya3D.MESH = "MESH"; Laya3D.MATERIAL = "MATERIAL"; Laya3D.TEXTURE2D = "TEXTURE2D"; Laya3D.TEXTURECUBE = "TEXTURECUBE"; Laya3D.TEXTURECUBEBIN = "TEXTURECUBEBIN"; Laya3D.ANIMATIONCLIP = "ANIMATIONCLIP"; Laya3D.AVATAR = "AVATAR"; Laya3D.TERRAINHEIGHTDATA = "TERRAINHEIGHTDATA"; Laya3D.TERRAINRES = "TERRAIN"; Laya3D._innerFirstLevelLoaderManager = new Laya.LoaderManager(); Laya3D._innerSecondLevelLoaderManager = new Laya.LoaderManager(); Laya3D._innerThirdLevelLoaderManager = new Laya.LoaderManager(); Laya3D._innerFourthLevelLoaderManager = new Laya.LoaderManager(); Laya3D._isInit = false; Laya3D._editerEnvironment = false; Laya3D.physicsSettings = new PhysicsSettings(); window.Laya3D = Laya3D; class CastShadowList extends SingletonList { constructor() { super(); } add(element) { var index = element._indexInCastShadowList; if (index !== -1) throw "CastShadowList:element has in CastShadowList."; this._add(element); element._indexInCastShadowList = this.length++; } remove(element) { var index = element._indexInCastShadowList; this.length--; if (index !== this.length) { var end = this.elements[this.length]; this.elements[index] = end; end._indexInCastShadowList = index; } element._indexInCastShadowList = -1; } } class AnimatorStateScript { constructor() { } onStateEnter() { } onStateUpdate() { } onStateExit() { } } class Script3D extends Laya.Component { constructor() { super(...arguments); this._indexInPool = -1; } get isSingleton() { return false; } _checkProcessTriggers() { var prototype = Script3D.prototype; if (this.onTriggerEnter !== prototype.onTriggerEnter) return true; if (this.onTriggerStay !== prototype.onTriggerStay) return true; if (this.onTriggerExit !== prototype.onTriggerExit) return true; return false; } _checkProcessCollisions() { var prototype = Script3D.prototype; if (this.onCollisionEnter !== prototype.onCollisionEnter) return true; if (this.onCollisionStay !== prototype.onCollisionStay) return true; if (this.onCollisionExit !== prototype.onCollisionExit) return true; return false; } _onAwake() { this.onAwake(); if (this.onStart !== Script3D.prototype.onStart) Laya.Laya.startTimer.callLater(this, this.onStart); } _onEnable() { this.owner._scene._addScript(this); this.onEnable(); } _onDisable() { this.owner._scene._removeScript(this); this.owner.offAllCaller(this); this.onDisable(); } _onDestroy() { var scripts = this.owner._scripts; scripts.splice(scripts.indexOf(this), 1); var sprite = this.owner; sprite._needProcessTriggers = false; for (var i = 0, n = scripts.length; i < n; i++) { if (scripts[i]._checkProcessTriggers()) { sprite._needProcessTriggers = true; break; } } sprite._needProcessCollisions = false; for (i = 0, n = scripts.length; i < n; i++) { if (scripts[i]._checkProcessCollisions()) { sprite._needProcessCollisions = true; break; } } this.onDestroy(); } _isScript() { return true; } _onAdded() { var sprite = this.owner; var scripts = sprite._scripts; scripts || (sprite._scripts = scripts = []); scripts.push(this); if (!sprite._needProcessCollisions) sprite._needProcessCollisions = this._checkProcessCollisions(); if (!sprite._needProcessTriggers) sprite._needProcessTriggers = this._checkProcessTriggers(); } onAwake() { } onEnable() { } onStart() { } onTriggerEnter(other) { } onTriggerStay(other) { } onTriggerExit(other) { } onCollisionEnter(collision) { } onCollisionStay(collision) { } onCollisionExit(collision) { } onJointBreak() { } onMouseDown() { } onMouseDrag() { } onMouseClick() { } onMouseUp() { } onMouseEnter() { } onMouseOver() { } onMouseOut() { } onUpdate() { } onLateUpdate() { } onPreRender() { } onPostRender() { } onDisable() { } onDestroy() { } } class HeightMap { constructor(width, height, minHeight, maxHeight) { this._datas = []; this._w = width; this._h = height; this._minHeight = minHeight; this._maxHeight = maxHeight; } static creatFromMesh(mesh, width, height, outCellSize) { var vertices = []; var indexs = []; var submesheCount = mesh.subMeshCount; for (var i = 0; i < submesheCount; i++) { var subMesh = mesh.getSubMesh(i); var vertexBuffer = subMesh._vertexBuffer; var verts = vertexBuffer.getFloat32Data(); var subMeshVertices = []; for (var j = 0; j < verts.length; j += vertexBuffer.vertexDeclaration.vertexStride / 4) { var position = new Vector3(verts[j + 0], verts[j + 1], verts[j + 2]); subMeshVertices.push(position); } vertices.push(subMeshVertices); var ib = subMesh._indexBuffer; indexs.push(ib.getData()); } var bounds = mesh.bounds; var minX = bounds.getMin().x; var minZ = bounds.getMin().z; var maxX = bounds.getMax().x; var maxZ = bounds.getMax().z; var minY = bounds.getMin().y; var maxY = bounds.getMax().y; var widthSize = maxX - minX; var heightSize = maxZ - minZ; var cellWidth = outCellSize.x = widthSize / (width - 1); var cellHeight = outCellSize.y = heightSize / (height - 1); var heightMap = new HeightMap(width, height, minY, maxY); var ray = HeightMap._tempRay; var rayDir = ray.direction; rayDir.x = 0; rayDir.y = -1; rayDir.z = 0; const heightOffset = 0.1; var rayY = maxY + heightOffset; ray.origin.y = rayY; for (var h = 0; h < height; h++) { var posZ = minZ + h * cellHeight; heightMap._datas[h] = []; for (var w = 0; w < width; w++) { var posX = minX + w * cellWidth; var rayOri = ray.origin; rayOri.x = posX; rayOri.z = posZ; var closestIntersection = HeightMap._getPosition(ray, vertices, indexs); heightMap._datas[h][w] = (closestIntersection === Number.MAX_VALUE) ? NaN : rayY - closestIntersection; } } return heightMap; } static createFromImage(texture, minHeight, maxHeight) { var textureWidth = texture.width; var textureHeight = texture.height; var heightMap = new HeightMap(textureWidth, textureHeight, minHeight, maxHeight); var compressionRatio = (maxHeight - minHeight) / 254; var pixelsInfo = texture.getPixels(); var index = 0; for (var h = 0; h < textureHeight; h++) { var colDatas = heightMap._datas[h] = []; for (var w = 0; w < textureWidth; w++) { var r = pixelsInfo[index++]; var g = pixelsInfo[index++]; var b = pixelsInfo[index++]; var a = pixelsInfo[index++]; if (r == 255 && g == 255 && b == 255 && a == 255) colDatas[w] = NaN; else { colDatas[w] = (r + g + b) / 3 * compressionRatio + minHeight; } } } return heightMap; } static _getPosition(ray, vertices, indexs) { var closestIntersection = Number.MAX_VALUE; for (var i = 0; i < vertices.length; i++) { var subMeshVertices = vertices[i]; var subMeshIndexes = indexs[i]; for (var j = 0; j < subMeshIndexes.length; j += 3) { var vertex1 = subMeshVertices[subMeshIndexes[j + 0]]; var vertex2 = subMeshVertices[subMeshIndexes[j + 1]]; var vertex3 = subMeshVertices[subMeshIndexes[j + 2]]; var intersection = Picker.rayIntersectsTriangle(ray, vertex1, vertex2, vertex3); if (!isNaN(intersection) && intersection < closestIntersection) { closestIntersection = intersection; } } } return closestIntersection; } get width() { return this._w; } get height() { return this._h; } get maxHeight() { return this._maxHeight; } get minHeight() { return this._minHeight; } _inBounds(row, col) { return row >= 0 && row < this._h && col >= 0 && col < this._w; } getHeight(row, col) { if (this._inBounds(row, col)) return this._datas[row][col]; else return NaN; } } HeightMap._tempRay = new Ray(new Vector3(), new Vector3()); class MeshTerrainSprite3D extends MeshSprite3D { constructor(mesh, heightMap, name = null) { super(mesh, name); this._heightMap = heightMap; this._cellSize = new Vector2(); } static createFromMesh(mesh, heightMapWidth, heightMapHeight, name = null) { var meshTerrainSprite3D = new MeshTerrainSprite3D(mesh, null, name); meshTerrainSprite3D._initCreateFromMesh(heightMapWidth, heightMapHeight); return meshTerrainSprite3D; } static createFromMeshAndHeightMap(mesh, texture, minHeight, maxHeight, name = null) { var meshTerrainSprite3D = new MeshTerrainSprite3D(mesh, null, name); meshTerrainSprite3D._initCreateFromMeshHeightMap(texture, minHeight, maxHeight); return meshTerrainSprite3D; } get minX() { var worldMat = this.transform.worldMatrix; var worldMatE = worldMat.elements; return this._minX * this._getScaleX() + worldMatE[12]; } get minZ() { var worldMat = this.transform.worldMatrix; var worldMatE = worldMat.elements; return this._minZ * this._getScaleZ() + worldMatE[14]; } get width() { return (this._heightMap.width - 1) * this._cellSize.x * this._getScaleX(); } get depth() { return (this._heightMap.height - 1) * this._cellSize.y * this._getScaleZ(); } _disableRotation() { var rotation = this.transform.rotation; rotation.x = 0; rotation.y = 0; rotation.z = 0; rotation.w = 1; this.transform.rotation = rotation; } _getScaleX() { var worldMat = this.transform.worldMatrix; var worldMatE = worldMat.elements; var m11 = worldMatE[0]; var m12 = worldMatE[1]; var m13 = worldMatE[2]; return Math.sqrt((m11 * m11) + (m12 * m12) + (m13 * m13)); } _getScaleZ() { var worldMat = this.transform.worldMatrix; var worldMatE = worldMat.elements; var m31 = worldMatE[8]; var m32 = worldMatE[9]; var m33 = worldMatE[10]; return Math.sqrt((m31 * m31) + (m32 * m32) + (m33 * m33)); } _initCreateFromMesh(heightMapWidth, heightMapHeight) { this._heightMap = HeightMap.creatFromMesh(this.meshFilter.sharedMesh, heightMapWidth, heightMapHeight, this._cellSize); var boundingBox = this.meshFilter.sharedMesh.bounds; var min = boundingBox.getMin(); var max = boundingBox.getMax(); this._minX = min.x; this._minZ = min.z; } _initCreateFromMeshHeightMap(texture, minHeight, maxHeight) { var boundingBox = this.meshFilter.sharedMesh.bounds; this._heightMap = HeightMap.createFromImage(texture, minHeight, maxHeight); this._computeCellSize(boundingBox); var min = boundingBox.getMin(); var max = boundingBox.getMax(); this._minX = min.x; this._minZ = min.z; } _computeCellSize(boundingBox) { var min = boundingBox.getMin(); var max = boundingBox.getMax(); var minX = min.x; var minZ = min.z; var maxX = max.x; var maxZ = max.z; var widthSize = maxX - minX; var heightSize = maxZ - minZ; this._cellSize.x = widthSize / (this._heightMap.width - 1); this._cellSize.y = heightSize / (this._heightMap.height - 1); } _update(state) { this._disableRotation(); } getHeight(x, z) { MeshTerrainSprite3D._tempVector3.x = x; MeshTerrainSprite3D._tempVector3.y = 0; MeshTerrainSprite3D._tempVector3.z = z; this._disableRotation(); var worldMat = this.transform.worldMatrix; worldMat.invert(MeshTerrainSprite3D._tempMatrix4x4); Vector3.transformCoordinate(MeshTerrainSprite3D._tempVector3, MeshTerrainSprite3D._tempMatrix4x4, MeshTerrainSprite3D._tempVector3); x = MeshTerrainSprite3D._tempVector3.x; z = MeshTerrainSprite3D._tempVector3.z; var c = (x - this._minX) / this._cellSize.x; var d = (z - this._minZ) / this._cellSize.y; var row = Math.floor(d); var col = Math.floor(c); var s = c - col; var t = d - row; var uy; var vy; var worldMatE = worldMat.elements; var m21 = worldMatE[4]; var m22 = worldMatE[5]; var m23 = worldMatE[6]; var scaleY = Math.sqrt((m21 * m21) + (m22 * m22) + (m23 * m23)); var translateY = worldMatE[13]; var h01 = this._heightMap.getHeight(row, col + 1); var h10 = this._heightMap.getHeight((row + 1), col); if (isNaN(h01) || isNaN(h10)) return NaN; if (s + t <= 1.0) { var h00 = this._heightMap.getHeight(row, col); if (isNaN(h00)) return NaN; uy = h01 - h00; vy = h10 - h00; return (h00 + s * uy + t * vy) * scaleY + translateY; } else { var h11 = this._heightMap.getHeight((row + 1), col + 1); if (isNaN(h11)) return NaN; uy = h10 - h11; vy = h01 - h11; return (h11 + (1.0 - s) * uy + (1.0 - t) * vy) * scaleY + translateY; } } } MeshTerrainSprite3D._tempVector3 = new Vector3(); MeshTerrainSprite3D._tempMatrix4x4 = new Matrix4x4(); class GradientDataVector2 { constructor() { this._currentLength = 0; this._elements = new Float32Array(12); } get gradientCount() { return this._currentLength / 3; } add(key, value) { if (this._currentLength < 8) { if ((this._currentLength === 6) && ((key !== 1))) { key = 1; console.log("GradientDataVector2 warning:the forth key is be force set to 1."); } this._elements[this._currentLength++] = key; this._elements[this._currentLength++] = value.x; this._elements[this._currentLength++] = value.y; } else { console.log("GradientDataVector2 warning:data count must lessEqual than 4"); } } cloneTo(destObject) { var destGradientDataVector2 = destObject; destGradientDataVector2._currentLength = this._currentLength; var destElements = destGradientDataVector2._elements; for (var i = 0, n = this._elements.length; i < n; i++) { destElements[i] = this._elements[i]; } } clone() { var destGradientDataVector2 = new GradientDataVector2(); this.cloneTo(destGradientDataVector2); return destGradientDataVector2; } } class PixelLineData { constructor() { this.startPosition = new Vector3(); this.endPosition = new Vector3(); this.startColor = new Color(); this.endColor = new Color(); } cloneTo(destObject) { this.startPosition.cloneTo(destObject.startPosition); this.endPosition.cloneTo(destObject.endPosition); this.startColor.cloneTo(destObject.startColor); this.endColor.cloneTo(destObject.endColor); } } class PostProcessEffect { constructor() { } render(context) { } } class BloomEffect extends PostProcessEffect { constructor() { super(); this._shader = null; this._shaderData = new ShaderData(); this._linearColor = new Color(); this._bloomTextureTexelSize = new Vector4(); this._shaderThreshold = new Vector4(); this._shaderParams = new Vector4(); this._pyramid = null; this._intensity = 0.0; this._threshold = 1.0; this._softKnee = 0.5; this._diffusion = 7.0; this._anamorphicRatio = 0.0; this._dirtIntensity = 0.0; this._shaderSetting = new Vector4(); this._dirtTileOffset = new Vector4(); this.clamp = 65472.0; this.color = new Color(1.0, 1.0, 1.0, 1.0); this.fastMode = false; this.dirtTexture = null; this._shader = Shader3D.find("PostProcessBloom"); this._pyramid = new Array(BloomEffect.MAXPYRAMIDSIZE * 2); } get intensity() { return this._intensity; } set intensity(value) { this._intensity = Math.max(value, 0.0); } get threshold() { return this._threshold; } set threshold(value) { this._threshold = Math.max(value, 0.0); } get softKnee() { return this._softKnee; } set softKnee(value) { this._softKnee = Math.min(Math.max(value, 0.0), 1.0); } get diffusion() { return this._diffusion; } set diffusion(value) { this._diffusion = Math.min(Math.max(value, 1), 10); } get anamorphicRatio() { return this._anamorphicRatio; } set anamorphicRatio(value) { this._anamorphicRatio = Math.min(Math.max(value, -1.0), 1.0); } get dirtIntensity() { return this._dirtIntensity; } set dirtIntensity(value) { this._dirtIntensity = Math.max(value, 0.0); } render(context) { var cmd = context.command; var viewport = context.camera.viewport; this._shaderData.setTexture(BloomEffect.SHADERVALUE_AUTOEXPOSURETEX, Laya.Texture2D.whiteTexture); var ratio = this._anamorphicRatio; var rw = ratio < 0 ? -ratio : 0; var rh = ratio > 0 ? ratio : 0; var tw = Math.floor(viewport.width / (2 - rw)); var th = Math.floor(viewport.height / (2 - rh)); var s = Math.max(tw, th); var logs; logs = Math.log2(s) + this._diffusion - 10; var logsInt = Math.floor(logs); var iterations = Math.min(Math.max(logsInt, 1), BloomEffect.MAXPYRAMIDSIZE); var sampleScale = 0.5 + logs - logsInt; this._shaderData.setNumber(BloomEffect.SHADERVALUE_SAMPLESCALE, sampleScale); var lthresh = Color.gammaToLinearSpace(this.threshold); var knee = lthresh * this._softKnee + 1e-5; this._shaderThreshold.setValue(lthresh, lthresh - knee, knee * 2, 0.25 / knee); this._shaderData.setVector(BloomEffect.SHADERVALUE_THRESHOLD, this._shaderThreshold); var lclamp = Color.gammaToLinearSpace(this.clamp); this._shaderParams.setValue(lclamp, 0, 0, 0); this._shaderData.setVector(BloomEffect.SHADERVALUE_PARAMS, this._shaderParams); var qualityOffset = this.fastMode ? 1 : 0; var lastDownTexture = context.source; for (var i = 0; i < iterations; i++) { var downIndex = i * 2; var upIndex = downIndex + 1; var subShader = i == 0 ? BloomEffect.SUBSHADER_PREFILTER13 + qualityOffset : BloomEffect.SUBSHADER_DOWNSAMPLE13 + qualityOffset; var mipDownTexture = RenderTexture.createFromPool(tw, th, Laya.RenderTextureFormat.R8G8B8, Laya.RenderTextureDepthFormat.DEPTHSTENCIL_NONE); mipDownTexture.filterMode = Laya.FilterMode.Bilinear; this._pyramid[downIndex] = mipDownTexture; if (i !== iterations - 1) { var mipUpTexture = RenderTexture.createFromPool(tw, th, Laya.RenderTextureFormat.R8G8B8, Laya.RenderTextureDepthFormat.DEPTHSTENCIL_NONE); mipUpTexture.filterMode = Laya.FilterMode.Bilinear; this._pyramid[upIndex] = mipUpTexture; } cmd.blitScreenTriangle(lastDownTexture, mipDownTexture, null, this._shader, this._shaderData, subShader); lastDownTexture = mipDownTexture; tw = Math.max(Math.floor(tw / 2), 1); th = Math.max(Math.floor(th / 2), 1); } var lastUpTexture = this._pyramid[(iterations - 1) * 2]; for (i = iterations - 2; i >= 0; i--) { downIndex = i * 2; upIndex = downIndex + 1; mipDownTexture = this._pyramid[downIndex]; mipUpTexture = this._pyramid[upIndex]; cmd.setShaderDataTexture(this._shaderData, BloomEffect.SHADERVALUE_BLOOMTEX, mipDownTexture); cmd.blitScreenTriangle(lastUpTexture, mipUpTexture, null, this._shader, this._shaderData, BloomEffect.SUBSHADER_UPSAMPLETENT + qualityOffset); lastUpTexture = mipUpTexture; } var linearColor = this._linearColor; this.color.toLinear(linearColor); var intensity = Math.pow(2, this._intensity / 10.0) - 1.0; var shaderSettings = this._shaderSetting; this._shaderSetting.setValue(sampleScale, intensity, this._dirtIntensity, iterations); var dirtTexture = this.dirtTexture ? this.dirtTexture : Laya.Texture2D.blackTexture; var dirtRatio = dirtTexture.width / dirtTexture.height; var screenRatio = viewport.width / viewport.height; var dirtTileOffset = this._dirtTileOffset; if (dirtRatio > screenRatio) dirtTileOffset.setValue(screenRatio / dirtRatio, 1.0, (1.0 - dirtTileOffset.x) * 0.5, 0.0); else if (dirtRatio < screenRatio) dirtTileOffset.setValue(1.0, dirtRatio / screenRatio, 0.0, (1.0 - dirtTileOffset.y) * 0.5); var compositeShaderData = context.compositeShaderData; if (this.fastMode) compositeShaderData.addDefine(PostProcess.SHADERDEFINE_BLOOM_LOW); else compositeShaderData.addDefine(PostProcess.SHADERDEFINE_BLOOM); this._bloomTextureTexelSize.setValue(1.0 / lastUpTexture.width, 1.0 / lastUpTexture.height, lastUpTexture.width, lastUpTexture.height); compositeShaderData.setVector(PostProcess.SHADERVALUE_BLOOM_DIRTTILEOFFSET, dirtTileOffset); compositeShaderData.setVector(PostProcess.SHADERVALUE_BLOOM_SETTINGS, shaderSettings); compositeShaderData.setVector(PostProcess.SHADERVALUE_BLOOM_COLOR, new Vector4(linearColor.r, linearColor.g, linearColor.b, linearColor.a)); compositeShaderData.setTexture(PostProcess.SHADERVALUE_BLOOM_DIRTTEX, dirtTexture); compositeShaderData.setTexture(PostProcess.SHADERVALUE_BLOOMTEX, lastUpTexture); compositeShaderData.setVector(PostProcess.SHADERVALUE_BLOOMTEX_TEXELSIZE, this._bloomTextureTexelSize); for (i = 0; i < iterations; i++) { downIndex = i * 2; upIndex = downIndex + 1; RenderTexture.recoverToPool(this._pyramid[downIndex]); (i !== 0 && i !== iterations - 1) && (RenderTexture.recoverToPool(this._pyramid[upIndex])); } context.deferredReleaseTextures.push(lastUpTexture); } } BloomEffect.SHADERVALUE_MAINTEX = Shader3D.propertyNameToID("u_MainTex"); BloomEffect.SHADERVALUE_AUTOEXPOSURETEX = Shader3D.propertyNameToID("u_AutoExposureTex"); BloomEffect.SHADERVALUE_SAMPLESCALE = Shader3D.propertyNameToID("u_SampleScale"); BloomEffect.SHADERVALUE_THRESHOLD = Shader3D.propertyNameToID("u_Threshold"); BloomEffect.SHADERVALUE_PARAMS = Shader3D.propertyNameToID("u_Params"); BloomEffect.SHADERVALUE_BLOOMTEX = Shader3D.propertyNameToID("u_BloomTex"); BloomEffect.SUBSHADER_PREFILTER13 = 0; BloomEffect.SUBSHADER_PREFILTER4 = 1; BloomEffect.SUBSHADER_DOWNSAMPLE13 = 2; BloomEffect.SUBSHADER_DOWNSAMPLE4 = 3; BloomEffect.SUBSHADER_UPSAMPLETENT = 4; BloomEffect.SUBSHADER_UPSAMPLEBOX = 5; BloomEffect.MAXPYRAMIDSIZE = 16; class SceneManager { constructor() { } } class RandX { constructor(seed) { if (!(seed instanceof Array) || seed.length !== 4) throw new Error('Rand:Seed must be an array with 4 numbers'); this._state0U = seed[0] | 0; this._state0L = seed[1] | 0; this._state1U = seed[2] | 0; this._state1L = seed[3] | 0; } randomint() { var s1U = this._state0U, s1L = this._state0L; var s0U = this._state1U, s0L = this._state1L; var sumL = (s0L >>> 0) + (s1L >>> 0); var resU = (s0U + s1U + (sumL / 2 >>> 31)) >>> 0; var resL = sumL >>> 0; this._state0U = s0U; this._state0L = s0L; var t1U = 0, t1L = 0; var t2U = 0, t2L = 0; var a1 = 23; var m1 = 0xFFFFFFFF << (32 - a1); t1U = (s1U << a1) | ((s1L & m1) >>> (32 - a1)); t1L = s1L << a1; s1U = s1U ^ t1U; s1L = s1L ^ t1L; t1U = s1U ^ s0U; t1L = s1L ^ s0L; var a2 = 18; var m2 = 0xFFFFFFFF >>> (32 - a2); t2U = s1U >>> a2; t2L = (s1L >>> a2) | ((s1U & m2) << (32 - a2)); t1U = t1U ^ t2U; t1L = t1L ^ t2L; var a3 = 5; var m3 = 0xFFFFFFFF >>> (32 - a3); t2U = s0U >>> a3; t2L = (s0L >>> a3) | ((s0U & m3) << (32 - a3)); t1U = t1U ^ t2U; t1L = t1L ^ t2L; this._state1U = t1U; this._state1L = t1L; return [resU, resL]; } random() { var t2 = this.randomint(); var t2U = t2[0]; var t2L = t2[1]; var eU = 0x3FF << (52 - 32); var eL = 0; var a1 = 12; var m1 = 0xFFFFFFFF >>> (32 - a1); var sU = t2U >>> a1; var sL = (t2L >>> a1) | ((t2U & m1) << (32 - a1)); var xU = eU | sU; var xL = eL | sL; RandX._CONVERTION_BUFFER.setUint32(0, xU, false); RandX._CONVERTION_BUFFER.setUint32(4, xL, false); var d = RandX._CONVERTION_BUFFER.getFloat64(0, false); return d - 1; } } RandX._CONVERTION_BUFFER = new DataView(new ArrayBuffer(8)); RandX.defaultRand = new RandX([0, Date.now() / 65536, 0, Date.now() % 65536]); class Constraint3D { constructor() { } } class Point2PointConstraint { constructor() { this._pivotInA = new Vector3(); this._pivotInB = new Vector3(); } get pivotInA() { return this._pivotInA; } set pivotInA(value) { this._pivotInA = value; } get pivotInB() { return this._pivotInB; } set pivotInB(value) { this._pivotInB = value; } get damping() { return this._damping; } set damping(value) { this._damping = value; } get impulseClamp() { return this._impulseClamp; } set impulseClamp(value) { this._impulseClamp = value; } get tau() { return this._tau; } set tau(value) { this._tau = value; } } class HeightfieldColliderShape { constructor() { } } class TextMesh { constructor() { } get text() { return this._text; } set text(value) { this._text = value; } get fontSize() { return this._fontSize; } set fontSize(value) { this._fontSize = value; } get color() { return this._color; } set color(value) { this._color = value; } _createVertexBuffer(charCount) { } _resizeVertexBuffer(charCount) { } _addChar() { } } class Size { constructor(width, height) { this._width = 0; this._height = 0; this._width = width; this._height = height; } static get fullScreen() { return new Size(-1, -1); } get width() { if (this._width === -1) return RenderContext3D.clientWidth; return this._width; } get height() { if (this._height === -1) return RenderContext3D.clientHeight; return this._height; } } exports.AlternateLightQueue = AlternateLightQueue; exports.AnimationClip = AnimationClip; exports.AnimationClipParser03 = AnimationClipParser03; exports.AnimationClipParser04 = AnimationClipParser04; exports.AnimationEvent = AnimationEvent; exports.AnimationNode = AnimationNode; exports.AnimationTransform3D = AnimationTransform3D; exports.Animator = Animator; exports.AnimatorControllerLayer = AnimatorControllerLayer; exports.AnimatorPlayState = AnimatorPlayState; exports.AnimatorState = AnimatorState; exports.AnimatorStateScript = AnimatorStateScript; exports.Avatar = Avatar; exports.BaseCamera = BaseCamera; exports.BaseMaterial = BaseMaterial; exports.BaseRender = BaseRender; exports.BaseShape = BaseShape; exports.BatchMark = BatchMark; exports.BlinnPhongMaterial = BlinnPhongMaterial; exports.BlitScreenQuadCMD = BlitScreenQuadCMD; exports.BloomEffect = BloomEffect; exports.BoundBox = BoundBox; exports.BoundFrustum = BoundFrustum; exports.BoundSphere = BoundSphere; exports.Bounds = Bounds; exports.BoundsOctree = BoundsOctree; exports.BoundsOctreeNode = BoundsOctreeNode; exports.BoxColliderShape = BoxColliderShape; exports.BoxShape = BoxShape; exports.BufferState = BufferState; exports.BulletInteractive = BulletInteractive; exports.Burst = Burst; exports.Camera = Camera; exports.CameraCullInfo = CameraCullInfo; exports.CapsuleColliderShape = CapsuleColliderShape; exports.CastShadowList = CastShadowList; exports.CharacterController = CharacterController; exports.CircleShape = CircleShape; exports.Cluster = Cluster; exports.ColliderShape = ColliderShape; exports.Collision = Collision; exports.CollisionTool = CollisionTool; exports.CollisionUtils = CollisionUtils; exports.Color = Color; exports.ColorOverLifetime = ColorOverLifetime; exports.Command = Command; exports.CommandBuffer = CommandBuffer; exports.CompoundColliderShape = CompoundColliderShape; exports.ConchQuaternion = ConchQuaternion; exports.ConchVector3 = ConchVector3; exports.ConchVector4 = ConchVector4; exports.ConeColliderShape = ConeColliderShape; exports.ConeShape = ConeShape; exports.Config3D = Config3D; exports.ConfigurableConstraint = ConfigurableConstraint; exports.Constraint3D = Constraint3D; exports.ConstraintComponent = ConstraintComponent; exports.ContactPoint = ContactPoint; exports.ContainmentType = ContainmentType; exports.CylinderColliderShape = CylinderColliderShape; exports.DefineDatas = DefineDatas; exports.DirectionLight = DirectionLight; exports.DynamicBatchManager = DynamicBatchManager; exports.EffectMaterial = EffectMaterial; exports.Emission = Emission; exports.ExtendTerrainMaterial = ExtendTerrainMaterial; exports.FixedConstraint = FixedConstraint; exports.FloatKeyframe = FloatKeyframe; exports.FrameOverTime = FrameOverTime; exports.FrustumCulling = FrustumCulling; exports.GeometryElement = GeometryElement; exports.Gradient = Gradient; exports.GradientAngularVelocity = GradientAngularVelocity; exports.GradientColor = GradientColor; exports.GradientDataInt = GradientDataInt; exports.GradientDataNumber = GradientDataNumber; exports.GradientDataVector2 = GradientDataVector2; exports.GradientMode = GradientMode; exports.GradientSize = GradientSize; exports.GradientVelocity = GradientVelocity; exports.HalfFloatUtils = HalfFloatUtils; exports.HeightMap = HeightMap; exports.HeightfieldColliderShape = HeightfieldColliderShape; exports.HemisphereShape = HemisphereShape; exports.HitResult = HitResult; exports.ILaya3D = ILaya3D; exports.IndexBuffer3D = IndexBuffer3D; exports.Input3D = Input3D; exports.Keyframe = Keyframe; exports.KeyframeNode = KeyframeNode; exports.KeyframeNodeList = KeyframeNodeList; exports.KeyframeNodeOwner = KeyframeNodeOwner; exports.Laya3D = Laya3D; exports.LightQueue = LightQueue; exports.LightSprite = LightSprite; exports.Lightmap = Lightmap; exports.LoadModelV04 = LoadModelV04; exports.LoadModelV05 = LoadModelV05; exports.Material = Material; exports.MathUtils3D = MathUtils3D; exports.Matrix3x3 = Matrix3x3; exports.Matrix4x4 = Matrix4x4; exports.Mesh = Mesh; exports.MeshColliderShape = MeshColliderShape; exports.MeshFilter = MeshFilter; exports.MeshReader = MeshReader; exports.MeshRenderDynamicBatchManager = MeshRenderDynamicBatchManager; exports.MeshRenderStaticBatchManager = MeshRenderStaticBatchManager; exports.MeshRenderer = MeshRenderer; exports.MeshSprite3D = MeshSprite3D; exports.MeshSprite3DShaderDeclaration = MeshSprite3DShaderDeclaration; exports.MeshTerrainSprite3D = MeshTerrainSprite3D; exports.MouseTouch = MouseTouch; exports.OctreeMotionList = OctreeMotionList; exports.PBRMaterial = PBRMaterial; exports.PBRSpecularMaterial = PBRSpecularMaterial; exports.PBRStandardMaterial = PBRStandardMaterial; exports.Physics3D = Physics3D; exports.Physics3DUtils = Physics3DUtils; exports.PhysicsCollider = PhysicsCollider; exports.PhysicsComponent = PhysicsComponent; exports.PhysicsSettings = PhysicsSettings; exports.PhysicsSimulation = PhysicsSimulation; exports.PhysicsTriggerComponent = PhysicsTriggerComponent; exports.PhysicsUpdateList = PhysicsUpdateList; exports.Picker = Picker; exports.PixelLineData = PixelLineData; exports.PixelLineFilter = PixelLineFilter; exports.PixelLineMaterial = PixelLineMaterial; exports.PixelLineRenderer = PixelLineRenderer; exports.PixelLineSprite3D = PixelLineSprite3D; exports.PixelLineVertex = PixelLineVertex; exports.Plane = Plane; exports.Point2PointConstraint = Point2PointConstraint; exports.PointLight = PointLight; exports.PostProcess = PostProcess; exports.PostProcessEffect = PostProcessEffect; exports.PostProcessRenderContext = PostProcessRenderContext; exports.PrimitiveMesh = PrimitiveMesh; exports.Quaternion = Quaternion; exports.QuaternionKeyframe = QuaternionKeyframe; exports.Rand = Rand; exports.RandX = RandX; exports.Ray = Ray; exports.RenderContext3D = RenderContext3D; exports.RenderElement = RenderElement; exports.RenderQueue = RenderQueue; exports.RenderState = RenderState; exports.RenderTexture = RenderTexture; exports.RenderableSprite3D = RenderableSprite3D; exports.Rigidbody3D = Rigidbody3D; exports.RotationOverLifetime = RotationOverLifetime; exports.Scene3D = Scene3D; exports.Scene3DShaderDeclaration = Scene3DShaderDeclaration; exports.Scene3DUtils = Scene3DUtils; exports.SceneManager = SceneManager; exports.ScreenQuad = ScreenQuad; exports.ScreenTriangle = ScreenTriangle; exports.Script3D = Script3D; exports.SetRenderTargetCMD = SetRenderTargetCMD; exports.SetShaderDataTextureCMD = SetShaderDataTextureCMD; exports.Shader3D = Shader3D; exports.ShaderData = ShaderData; exports.ShaderDefine = ShaderDefine; exports.ShaderInit3D = ShaderInit3D; exports.ShaderInstance = ShaderInstance; exports.ShaderPass = ShaderPass; exports.ShaderVariable = ShaderVariable; exports.ShaderVariant = ShaderVariant; exports.ShaderVariantCollection = ShaderVariantCollection; exports.ShadowCasterPass = ShadowCasterPass; exports.ShadowCullInfo = ShadowCullInfo; exports.ShadowSliceData = ShadowSliceData; exports.ShadowSpotData = ShadowSpotData; exports.ShadowUtils = ShadowUtils; exports.ShapeUtils = ShapeUtils; exports.ShuriKenParticle3D = ShuriKenParticle3D; exports.ShuriKenParticle3DShaderDeclaration = ShuriKenParticle3DShaderDeclaration; exports.ShurikenParticleData = ShurikenParticleData; exports.ShurikenParticleMaterial = ShurikenParticleMaterial; exports.ShurikenParticleRenderer = ShurikenParticleRenderer; exports.ShurikenParticleSystem = ShurikenParticleSystem; exports.SimpleSingletonList = SimpleSingletonList; exports.SingletonList = SingletonList; exports.Size = Size; exports.SizeOverLifetime = SizeOverLifetime; exports.SkinnedMeshRenderer = SkinnedMeshRenderer; exports.SkinnedMeshSprite3D = SkinnedMeshSprite3D; exports.SkinnedMeshSprite3DShaderDeclaration = SkinnedMeshSprite3DShaderDeclaration; exports.SkyBox = SkyBox; exports.SkyBoxMaterial = SkyBoxMaterial; exports.SkyDome = SkyDome; exports.SkyMesh = SkyMesh; exports.SkyPanoramicMaterial = SkyPanoramicMaterial; exports.SkyProceduralMaterial = SkyProceduralMaterial; exports.SkyRenderer = SkyRenderer; exports.SphereColliderShape = SphereColliderShape; exports.SphereShape = SphereShape; exports.SphericalHarmonicsL2 = SphericalHarmonicsL2; exports.SpotLight = SpotLight; exports.Sprite3D = Sprite3D; exports.StartFrame = StartFrame; exports.StaticBatchManager = StaticBatchManager; exports.StaticPlaneColliderShape = StaticPlaneColliderShape; exports.SubMesh = SubMesh; exports.SubMeshDynamicBatch = SubMeshDynamicBatch; exports.SubMeshInstanceBatch = SubMeshInstanceBatch; exports.SubMeshRenderElement = SubMeshRenderElement; exports.SubMeshStaticBatch = SubMeshStaticBatch; exports.SubShader = SubShader; exports.TextMesh = TextMesh; exports.TextureCube = TextureCube; exports.TextureGenerator = TextureGenerator; exports.TextureMode = TextureMode; exports.TextureSheetAnimation = TextureSheetAnimation; exports.Touch = Touch; exports.TrailFilter = TrailFilter; exports.TrailGeometry = TrailGeometry; exports.TrailMaterial = TrailMaterial; exports.TrailRenderer = TrailRenderer; exports.TrailSprite3D = TrailSprite3D; exports.Transform3D = Transform3D; exports.UnlitMaterial = UnlitMaterial; exports.Utils3D = Utils3D; exports.Vector2 = Vector2; exports.Vector3 = Vector3; exports.Vector3Keyframe = Vector3Keyframe; exports.Vector4 = Vector4; exports.VelocityOverLifetime = VelocityOverLifetime; exports.VertexBuffer3D = VertexBuffer3D; exports.VertexDeclaration = VertexDeclaration; exports.VertexElement = VertexElement; exports.VertexElementFormat = VertexElementFormat; exports.VertexMesh = VertexMesh; exports.VertexPositionTerrain = VertexPositionTerrain; exports.VertexPositionTexture0 = VertexPositionTexture0; exports.VertexShuriKenParticle = VertexShuriKenParticle; exports.VertexShurikenParticleBillboard = VertexShurikenParticleBillboard; exports.VertexShurikenParticleMesh = VertexShurikenParticleMesh; exports.VertexTrail = VertexTrail; exports.Viewport = Viewport; exports.WaterPrimaryMaterial = WaterPrimaryMaterial; exports.skinnedMatrixCache = skinnedMatrixCache; }(window.Laya = window.Laya || {}, Laya));