|
@@ -12,6 +12,7 @@ import { AssetContainer } from "babylonjs/assetContainer";
|
|
import { Scene } from "babylonjs/scene";
|
|
import { Scene } from "babylonjs/scene";
|
|
import { WebRequest } from 'babylonjs/Misc/webRequest';
|
|
import { WebRequest } from 'babylonjs/Misc/webRequest';
|
|
import { MTLFileLoader } from './mtlFileLoader';
|
|
import { MTLFileLoader } from './mtlFileLoader';
|
|
|
|
+import { VertexBuffer } from "babylonjs/Meshes/buffer";
|
|
|
|
|
|
type MeshObject = {
|
|
type MeshObject = {
|
|
name: string;
|
|
name: string;
|
|
@@ -52,6 +53,11 @@ type MeshLoadOptions = {
|
|
*/
|
|
*/
|
|
ComputeNormals: boolean,
|
|
ComputeNormals: boolean,
|
|
/**
|
|
/**
|
|
|
|
+ * Optimize the normals for the model. Lighting can be uneven if you use OptimizeWithUV = true because new vertices can be created for the same location if they pertain to different faces.
|
|
|
|
+ * Using OptimizehNormals = true will help smoothing the lighting by averaging the normals of those vertices.
|
|
|
|
+ */
|
|
|
|
+ OptimizeNormals: boolean,
|
|
|
|
+ /**
|
|
* Skip loading the materials even if defined in the OBJ file (materials are ignored).
|
|
* Skip loading the materials even if defined in the OBJ file (materials are ignored).
|
|
*/
|
|
*/
|
|
SkipMaterials: boolean,
|
|
SkipMaterials: boolean,
|
|
@@ -95,6 +101,11 @@ export class OBJFileLoader implements ISceneLoaderPluginAsync, ISceneLoaderPlugi
|
|
*/
|
|
*/
|
|
public static COMPUTE_NORMALS = false;
|
|
public static COMPUTE_NORMALS = false;
|
|
/**
|
|
/**
|
|
|
|
+ * Optimize the normals for the model. Lighting can be uneven if you use OptimizeWithUV = true because new vertices can be created for the same location if they pertain to different faces.
|
|
|
|
+ * Using OptimizehNormals = true will help smoothing the lighting by averaging the normals of those vertices.
|
|
|
|
+ */
|
|
|
|
+ public static OPTIMIZE_NORMALS = false;
|
|
|
|
+ /**
|
|
* Defines custom scaling of UV coordinates of loaded meshes.
|
|
* Defines custom scaling of UV coordinates of loaded meshes.
|
|
*/
|
|
*/
|
|
public static UV_SCALING = new Vector2(1, 1);
|
|
public static UV_SCALING = new Vector2(1, 1);
|
|
@@ -167,6 +178,7 @@ export class OBJFileLoader implements ISceneLoaderPluginAsync, ISceneLoaderPlugi
|
|
private static get currentMeshLoadOptions(): MeshLoadOptions {
|
|
private static get currentMeshLoadOptions(): MeshLoadOptions {
|
|
return {
|
|
return {
|
|
ComputeNormals: OBJFileLoader.COMPUTE_NORMALS,
|
|
ComputeNormals: OBJFileLoader.COMPUTE_NORMALS,
|
|
|
|
+ OptimizeNormals: OBJFileLoader.OPTIMIZE_NORMALS,
|
|
ImportVertexColors: OBJFileLoader.IMPORT_VERTEX_COLORS,
|
|
ImportVertexColors: OBJFileLoader.IMPORT_VERTEX_COLORS,
|
|
InvertY: OBJFileLoader.INVERT_Y,
|
|
InvertY: OBJFileLoader.INVERT_Y,
|
|
InvertTextureY: OBJFileLoader.INVERT_TEXTURE_Y,
|
|
InvertTextureY: OBJFileLoader.INVERT_TEXTURE_Y,
|
|
@@ -304,6 +316,58 @@ export class OBJFileLoader implements ISceneLoaderPluginAsync, ISceneLoaderPlugi
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private _optimizeNormals(mesh: AbstractMesh): void {
|
|
|
|
+ const positions = mesh.getVerticesData(VertexBuffer.PositionKind);
|
|
|
|
+ const normals = mesh.getVerticesData(VertexBuffer.NormalKind);
|
|
|
|
+ const mapVertices: { [key: string]: number[] } = {};
|
|
|
|
+
|
|
|
|
+ if (!positions || !normals) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (let i = 0; i < positions.length / 3; i++) {
|
|
|
|
+ const x = positions[i * 3 + 0];
|
|
|
|
+ const y = positions[i * 3 + 1];
|
|
|
|
+ const z = positions[i * 3 + 2];
|
|
|
|
+ const key = x + "_" + y + "_" + z;
|
|
|
|
+
|
|
|
|
+ let lst = mapVertices[key];
|
|
|
|
+ if (!lst) {
|
|
|
|
+ lst = [];
|
|
|
|
+ mapVertices[key] = lst;
|
|
|
|
+ }
|
|
|
|
+ lst.push(i);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const normal = new Vector3();
|
|
|
|
+ for (const key in mapVertices) {
|
|
|
|
+ const lst = mapVertices[key];
|
|
|
|
+ if (lst.length < 2) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const v0Idx = lst[0];
|
|
|
|
+ for (let i = 1; i < lst.length; ++i) {
|
|
|
|
+ const vIdx = lst[i];
|
|
|
|
+ normals[v0Idx * 3 + 0] += normals[vIdx * 3 + 0];
|
|
|
|
+ normals[v0Idx * 3 + 1] += normals[vIdx * 3 + 1];
|
|
|
|
+ normals[v0Idx * 3 + 2] += normals[vIdx * 3 + 2];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ normal.copyFromFloats(normals[v0Idx * 3 + 0], normals[v0Idx * 3 + 1], normals[v0Idx * 3 + 2]);
|
|
|
|
+ normal.normalize();
|
|
|
|
+
|
|
|
|
+ for (let i = 0; i < lst.length; ++i) {
|
|
|
|
+ const vIdx = lst[i];
|
|
|
|
+ normals[vIdx * 3 + 0] = normal.x;
|
|
|
|
+ normals[vIdx * 3 + 1] = normal.y;
|
|
|
|
+ normals[vIdx * 3 + 2] = normal.z;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mesh.setVerticesData(VertexBuffer.NormalKind, normals);
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Read the OBJ file and create an Array of meshes.
|
|
* Read the OBJ file and create an Array of meshes.
|
|
* Each mesh contains all information given by the OBJ and the MTL file.
|
|
* Each mesh contains all information given by the OBJ and the MTL file.
|
|
@@ -956,6 +1020,9 @@ export class OBJFileLoader implements ISceneLoaderPluginAsync, ISceneLoaderPlugi
|
|
if (this._meshLoadOptions.InvertY) {
|
|
if (this._meshLoadOptions.InvertY) {
|
|
babylonMesh.scaling.y *= -1;
|
|
babylonMesh.scaling.y *= -1;
|
|
}
|
|
}
|
|
|
|
+ if (this._meshLoadOptions.OptimizeNormals === true) {
|
|
|
|
+ this._optimizeNormals(babylonMesh);
|
|
|
|
+ }
|
|
|
|
|
|
//Push the mesh into an array
|
|
//Push the mesh into an array
|
|
babylonMeshesArray.push(babylonMesh);
|
|
babylonMeshesArray.push(babylonMesh);
|