From cba71f92fa51784258c590a91ea56b3c438359d8 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Sun, 15 Oct 2023 21:40:19 +0200 Subject: [PATCH 01/29] Add lines to the mesh data structure. --- source/engine/main.js | 10 +++++--- source/engine/model/line.js | 28 +++++++++++++++++++++ source/engine/model/material.js | 13 ++++++++-- source/engine/model/mesh.js | 22 ++++++++++++++++ source/engine/model/meshinstance.js | 5 ++++ source/engine/model/meshutils.js | 13 ++-------- source/engine/model/model.js | 9 +++++++ source/engine/model/modelfinalization.js | 32 ++++++++++++++++++++---- source/engine/model/modelutils.js | 4 +-- source/engine/threejs/threeconverter.js | 5 ++-- test/tests/mesh_test.js | 10 ++++++++ test/tests/model_test.js | 19 ++++++++++++++ 12 files changed, 143 insertions(+), 27 deletions(-) create mode 100644 source/engine/model/line.js diff --git a/source/engine/main.js b/source/engine/main.js index 0420924..84b9ddf 100644 --- a/source/engine/main.js +++ b/source/engine/main.js @@ -46,11 +46,12 @@ import { GetFileName, GetFileExtension, RequestUrl, ReadFile, TransformFileHostU import { TextWriter } from './io/textwriter.js'; import { RGBColor, RGBAColor, ColorComponentFromFloat, ColorComponentToFloat, RGBColorFromFloatComponents, SRGBToLinear, LinearToSRGB, IntegerToHexString, RGBColorToHexString, RGBAColorToHexString, HexStringToRGBColor, HexStringToRGBAColor, ArrayToRGBColor, RGBColorIsEqual } from './model/color.js'; import { GeneratorParams, Generator, GeneratorHelper, GenerateCuboid, GenerateCone, GenerateCylinder, GenerateSphere, GeneratePlatonicSolid } from './model/generator.js'; -import { TextureMap, MaterialBase, FaceMaterial, PhongMaterial, PhysicalMaterial, TextureMapIsEqual, TextureIsEqual, MaterialType } from './model/material.js'; +import { Line } from './model/line.js'; +import { TextureMap, MaterialBase, LineMaterial, FaceMaterial, PhongMaterial, PhysicalMaterial, TextureMapIsEqual, TextureIsEqual, MaterialType } from './model/material.js'; import { Mesh } from './model/mesh.js'; import { MeshPrimitiveBuffer, MeshBuffer, ConvertMeshToMeshBuffer } from './model/meshbuffer.js'; import { MeshInstanceId, MeshInstance } from './model/meshinstance.js'; -import { GetMeshType, CalculateTriangleNormal, TransformMesh, FlipMeshTrianglesOrientation, MeshType } from './model/meshutils.js'; +import { IsEmptyMesh, CalculateTriangleNormal, TransformMesh, FlipMeshTrianglesOrientation } from './model/meshutils.js'; import { Model } from './model/model.js'; import { FinalizeModel, CheckModel } from './model/modelfinalization.js'; import { IsModelEmpty, GetBoundingBox, GetTopology, IsTwoManifold, HasDefaultMaterial, ReplaceDefaultMaterialColor } from './model/modelutils.js'; @@ -226,8 +227,10 @@ export { GenerateCylinder, GenerateSphere, GeneratePlatonicSolid, + Line, TextureMap, MaterialBase, + LineMaterial, FaceMaterial, PhongMaterial, PhysicalMaterial, @@ -240,11 +243,10 @@ export { ConvertMeshToMeshBuffer, MeshInstanceId, MeshInstance, - GetMeshType, + IsEmptyMesh, CalculateTriangleNormal, TransformMesh, FlipMeshTrianglesOrientation, - MeshType, Model, FinalizeModel, CheckModel, diff --git a/source/engine/model/line.js b/source/engine/model/line.js new file mode 100644 index 0000000..c753972 --- /dev/null +++ b/source/engine/model/line.js @@ -0,0 +1,28 @@ +export class Line +{ + constructor (v0, v1) + { + this.v0 = v0; + this.v1 = v1; + + this.mat = null; + } + + HasVertices () + { + return this.v0 !== null && this.v1 !== null; + } + + SetMaterial (mat) + { + this.mat = mat; + return this; + } + + Clone () + { + let cloned = new Line (this.v0, this.v1); + cloned.SetMaterial (this.mat); + return cloned; + } +} diff --git a/source/engine/model/material.js b/source/engine/model/material.js index a77a19c..50a1bb3 100644 --- a/source/engine/model/material.js +++ b/source/engine/model/material.js @@ -66,8 +66,9 @@ export function TextureMapIsEqual (aTex, bTex) export const MaterialType = { - Phong : 1, - Physical : 2 + Line : 1, + Phong : 2, + Physical : 3 }; export class MaterialBase @@ -104,6 +105,14 @@ export class MaterialBase } } +export class LineMaterial extends MaterialBase +{ + constructor (type) + { + super (MaterialType.Line); + } +} + export class FaceMaterial extends MaterialBase { constructor (type) diff --git a/source/engine/model/mesh.js b/source/engine/model/mesh.js index 144f2e9..753d9d4 100644 --- a/source/engine/model/mesh.js +++ b/source/engine/model/mesh.js @@ -9,6 +9,7 @@ export class Mesh extends ModelObject3D this.vertexColors = []; this.normals = []; this.uvs = []; + this.lines = []; this.triangles = []; } @@ -32,6 +33,11 @@ export class Mesh extends ModelObject3D return this.uvs.length; } + LineCount () + { + return this.lines.length; + } + TriangleCount () { return this.triangles.length; @@ -101,6 +107,17 @@ SetNormal (index, normal) return this.uvs[index]; } + AddLine (line) + { + this.lines.push (line); + return this.lines.length - 1; + } + + GetLine (index) + { + return this.lines[index]; + } + AddTriangle (triangle) { this.triangles.push (triangle); @@ -163,6 +180,11 @@ SetNormal (index, normal) cloned.AddTextureUV (uv.Clone ()); } + for (let i = 0; i < this.LineCount (); i++) { + let line = this.GetLine (i); + cloned.AddLine (line.Clone ()); + } + for (let i = 0; i < this.TriangleCount (); i++) { let triangle = this.GetTriangle (i); cloned.AddTriangle (triangle.Clone ()); diff --git a/source/engine/model/meshinstance.js b/source/engine/model/meshinstance.js index ff79d49..8b5b49a 100644 --- a/source/engine/model/meshinstance.js +++ b/source/engine/model/meshinstance.js @@ -65,6 +65,11 @@ export class MeshInstance extends ModelObject3D return this.mesh.TextureUVCount (); } + LineCount () + { + return this.mesh.LineCount (); + } + TriangleCount () { return this.mesh.TriangleCount (); diff --git a/source/engine/model/meshutils.js b/source/engine/model/meshutils.js index 372f630..19ec08e 100644 --- a/source/engine/model/meshutils.js +++ b/source/engine/model/meshutils.js @@ -1,18 +1,9 @@ import { CrossVector3D, SubCoord3D } from '../geometry/coord3d.js'; import { Transformation } from '../geometry/transformation.js'; -export const MeshType = +export function IsEmptyMesh (mesh) { - Empty : 0, - TriangleMesh : 1 -}; - -export function GetMeshType (mesh) -{ - if (mesh.TriangleCount () > 0) { - return MeshType.TriangleMesh; - } - return MeshType.Empty; + return mesh.LineCount () === 0 && mesh.TriangleCount () === 0; } export function CalculateTriangleNormal (v0, v1, v2) diff --git a/source/engine/model/model.js b/source/engine/model/model.js index 562757c..f8e32cb 100644 --- a/source/engine/model/model.js +++ b/source/engine/model/model.js @@ -93,6 +93,15 @@ export class Model extends ModelObject3D return count; } + LineCount () + { + let count = 0; + this.EnumerateMeshInstances ((meshInstance) => { + count += meshInstance.LineCount (); + }); + return count; + } + TriangleCount () { let count = 0; diff --git a/source/engine/model/modelfinalization.js b/source/engine/model/modelfinalization.js index 2408e4e..7746663 100644 --- a/source/engine/model/modelfinalization.js +++ b/source/engine/model/modelfinalization.js @@ -1,19 +1,23 @@ import { CopyObjectAttributes } from '../core/core.js'; import { AddCoord3D, Coord3D, CoordIsEqual3D } from '../geometry/coord3d.js'; import { RGBColor } from './color.js'; -import { PhongMaterial } from './material.js'; -import { CalculateTriangleNormal, GetMeshType, MeshType } from './meshutils.js'; +import { LineMaterial, PhongMaterial } from './material.js'; +import { CalculateTriangleNormal, IsEmptyMesh } from './meshutils.js'; class ModelFinalizer { constructor (params) { this.params = { + getDefaultLineMaterialColor : () => { + return new RGBColor (0, 0, 0); + }, getDefaultMaterialColor : () => { return new RGBColor (0, 0, 0); } }; CopyObjectAttributes (params, this.params); + this.defaultLineMaterialIndex = null; this.defaultMaterialIndex = null; } @@ -56,8 +60,7 @@ class ModelFinalizer { for (let meshIndex = 0; meshIndex < model.MeshCount (); meshIndex++) { let mesh = model.GetMesh (meshIndex); - let type = GetMeshType (mesh); - if (type === MeshType.Empty) { + if (IsEmptyMesh (mesh)) { model.RemoveMesh (meshIndex); meshIndex = meshIndex - 1; continue; @@ -139,10 +142,16 @@ class ModelFinalizer calculateCurveNormals : false }; + for (let i = 0; i < mesh.LineCount (); i++) { + let line = mesh.GetLine (i); + if (line.mat === null) { + line.mat = this.GetDefaultLineMaterialIndex (model); + } + } + for (let i = 0; i < mesh.TriangleCount (); i++) { let triangle = mesh.GetTriangle (i); this.FinalizeTriangle (mesh, triangle, meshStatus); - if (triangle.mat === null) { triangle.mat = this.GetDefaultMaterialIndex (model); } @@ -197,6 +206,18 @@ class ModelFinalizer } } + GetDefaultLineMaterialIndex (model) + { + if (this.defaultLineMaterialIndex === null) { + let defaultLineMaterialColor = this.params.getDefaultLineMaterialColor (); + let defaultMaterial = new LineMaterial (); + defaultMaterial.color = defaultLineMaterialColor; + defaultMaterial.isDefault = true; + this.defaultLineMaterialIndex = model.AddMaterial (defaultMaterial); + } + return this.defaultLineMaterialIndex; + } + GetDefaultMaterialIndex (model) { if (this.defaultMaterialIndex === null) { @@ -211,6 +232,7 @@ class ModelFinalizer Reset () { + this.defaultLineMaterialIndex = null; this.defaultMaterialIndex = null; } } diff --git a/source/engine/model/modelutils.js b/source/engine/model/modelutils.js index 19a779c..064ba3e 100644 --- a/source/engine/model/modelutils.js +++ b/source/engine/model/modelutils.js @@ -1,6 +1,6 @@ import { BoundingBoxCalculator3D } from '../geometry/box3d.js'; import { Octree } from '../geometry/octree.js'; -import { GetMeshType, MeshType } from './meshutils.js'; +import { IsEmptyMesh } from './meshutils.js'; import { Model } from './model.js'; import { Topology } from './topology.js'; @@ -8,7 +8,7 @@ export function IsModelEmpty (model) { let isEmpty = true; model.EnumerateMeshInstances ((meshInstance) => { - if (GetMeshType (meshInstance) !== MeshType.Empty) { + if (!IsEmptyMesh (meshInstance)) { isEmpty = false; } }); diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index 954576f..a458209 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -3,7 +3,7 @@ import { IsEqual } from '../geometry/geometry.js'; import { CreateObjectUrl, CreateObjectUrlWithMimeType } from '../io/bufferutils.js'; import { MaterialType } from '../model/material.js'; import { MeshInstance, MeshInstanceId } from '../model/meshinstance.js'; -import { GetMeshType, MeshType } from '../model/meshutils.js'; +import { IsEmptyMesh } from '../model/meshutils.js'; import { ConvertColorToThreeColor, GetShadingType, ShadingType } from './threeutils.js'; import * as THREE from 'three'; @@ -329,8 +329,7 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) function ConvertMesh (threeObject, meshInstance, modelThreeMaterials) { - let type = GetMeshType (meshInstance.mesh); - if (type === MeshType.TriangleMesh) { + if (!IsEmptyMesh (meshInstance.mesh)) { let threeMesh = CreateThreeMesh (meshInstance, modelThreeMaterials); threeObject.add (threeMesh); } diff --git a/test/tests/mesh_test.js b/test/tests/mesh_test.js index 1ad2fd4..df101b6 100644 --- a/test/tests/mesh_test.js +++ b/test/tests/mesh_test.js @@ -52,6 +52,16 @@ describe ('Mesh', function() { assert.strictEqual (uv.y, 2.0); }); + it ('Add Line', function () { + var mesh = new OV.Mesh (); + var index = mesh.AddLine (new OV.Line (0, 1)); + assert.strictEqual (index, 0); + assert.strictEqual (mesh.LineCount (), 1); + var line = mesh.GetLine (index); + assert.strictEqual (line.v0, 0); + assert.strictEqual (line.v1, 1); + }); + it ('Add Triangle', function () { var mesh = new OV.Mesh (); var triangle = new OV.Triangle (1, 2, 3); diff --git a/test/tests/model_test.js b/test/tests/model_test.js index 21fa088..97857cb 100644 --- a/test/tests/model_test.js +++ b/test/tests/model_test.js @@ -41,6 +41,9 @@ describe ('Model', function () { mesh.AddNormal (new OV.Coord3D (0.0, 0.0, 0.0)); mesh.AddNormal (new OV.Coord3D (0.0, 0.0, 0.0)); mesh.AddTextureUV (new OV.Coord2D (0.0, 0.0)); + mesh.AddLine (new OV.Line (0, 1)); + mesh.AddLine (new OV.Line (1, 2)); + mesh.AddLine (new OV.Line (2, 0)); mesh.AddTriangle (new OV.Triangle (0, 1, 2)); mesh.AddTriangle (new OV.Triangle (0, 1, 2)); mesh.AddTriangle (new OV.Triangle (0, 1, 2)); @@ -49,6 +52,7 @@ describe ('Model', function () { assert.strictEqual (model.VertexCount (), 3); assert.strictEqual (model.NormalCount (), 2); assert.strictEqual (model.TextureUVCount (), 1); + assert.strictEqual (model.LineCount (), 3); assert.strictEqual (model.TriangleCount (), 4); }); @@ -86,6 +90,21 @@ describe ('Model', function () { }); describe ('Model Finalization', function () { + it ('Create Default Material', function () { + var mesh = new OV.Mesh (); + var v0 = mesh.AddVertex (new OV.Coord3D (0.0, 0.0, 0.0)); + var v1 = mesh.AddVertex (new OV.Coord3D (1.0, 0.0, 0.0)); + var v2 = mesh.AddVertex (new OV.Coord3D (1.0, 1.0, 0.0)); + mesh.AddLine (new OV.Line (v0, v1)); + mesh.AddTriangle (new OV.Triangle (v0, v1, v2)); + var model = new OV.Model (); + model.AddMesh (mesh); + OV.FinalizeModel (model); + assert.strictEqual (model.MaterialCount (), 2); + assert.strictEqual (model.GetMaterial (0).type, OV.MaterialType.Line); + assert.strictEqual (model.GetMaterial (1).type, OV.MaterialType.Phong); + }); + it ('Calculate Normal', function () { var mesh = new OV.Mesh (); var v0 = mesh.AddVertex (new OV.Coord3D (0.0, 0.0, 0.0)); From 4361240842f544464c7166c66c1a8df861480453 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 16 Oct 2023 21:55:17 +0200 Subject: [PATCH 02/29] Replace callbacks with color values. --- source/engine/import/importerbase.js | 2 +- source/engine/model/modelfinalization.js | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/source/engine/import/importerbase.js b/source/engine/import/importerbase.js index c9a37a3..58dc987 100644 --- a/source/engine/import/importerbase.js +++ b/source/engine/import/importerbase.js @@ -58,7 +58,7 @@ export class ImporterBase } FinalizeModel (this.model, { - getDefaultMaterialColor : this.callbacks.getDefaultMaterialColor + defaultMaterialColor : this.callbacks.getDefaultMaterialColor () }); callbacks.onSuccess (); diff --git a/source/engine/model/modelfinalization.js b/source/engine/model/modelfinalization.js index 7746663..04e68b4 100644 --- a/source/engine/model/modelfinalization.js +++ b/source/engine/model/modelfinalization.js @@ -9,12 +9,8 @@ class ModelFinalizer constructor (params) { this.params = { - getDefaultLineMaterialColor : () => { - return new RGBColor (0, 0, 0); - }, - getDefaultMaterialColor : () => { - return new RGBColor (0, 0, 0); - } + defaultLineMaterialColor : new RGBColor (0, 0, 0), + defaultMaterialColor : new RGBColor (0, 0, 0) }; CopyObjectAttributes (params, this.params); this.defaultLineMaterialIndex = null; @@ -209,9 +205,8 @@ class ModelFinalizer GetDefaultLineMaterialIndex (model) { if (this.defaultLineMaterialIndex === null) { - let defaultLineMaterialColor = this.params.getDefaultLineMaterialColor (); let defaultMaterial = new LineMaterial (); - defaultMaterial.color = defaultLineMaterialColor; + defaultMaterial.color = this.params.defaultLineMaterialColor; defaultMaterial.isDefault = true; this.defaultLineMaterialIndex = model.AddMaterial (defaultMaterial); } @@ -221,9 +216,8 @@ class ModelFinalizer GetDefaultMaterialIndex (model) { if (this.defaultMaterialIndex === null) { - let defaultMaterialColor = this.params.getDefaultMaterialColor (); let defaultMaterial = new PhongMaterial (); - defaultMaterial.color = defaultMaterialColor; + defaultMaterial.color = this.params.defaultMaterialColor; defaultMaterial.isDefault = true; this.defaultMaterialIndex = model.AddMaterial (defaultMaterial); } From f546ce65c0ab9ddb2683c4f2d29a3c93d36d15b6 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 17 Oct 2023 17:58:31 +0200 Subject: [PATCH 03/29] No need to have a separate material for lines. --- source/engine/main.js | 3 +- source/engine/model/line.js | 10 ++--- source/engine/model/material.js | 13 +------ source/engine/model/modelfinalization.js | 47 ++++++++++++++---------- test/tests/mesh_test.js | 6 +-- test/tests/model_test.js | 20 ++++++---- 6 files changed, 51 insertions(+), 48 deletions(-) diff --git a/source/engine/main.js b/source/engine/main.js index 84b9ddf..3ef9349 100644 --- a/source/engine/main.js +++ b/source/engine/main.js @@ -47,7 +47,7 @@ import { TextWriter } from './io/textwriter.js'; import { RGBColor, RGBAColor, ColorComponentFromFloat, ColorComponentToFloat, RGBColorFromFloatComponents, SRGBToLinear, LinearToSRGB, IntegerToHexString, RGBColorToHexString, RGBAColorToHexString, HexStringToRGBColor, HexStringToRGBAColor, ArrayToRGBColor, RGBColorIsEqual } from './model/color.js'; import { GeneratorParams, Generator, GeneratorHelper, GenerateCuboid, GenerateCone, GenerateCylinder, GenerateSphere, GeneratePlatonicSolid } from './model/generator.js'; import { Line } from './model/line.js'; -import { TextureMap, MaterialBase, LineMaterial, FaceMaterial, PhongMaterial, PhysicalMaterial, TextureMapIsEqual, TextureIsEqual, MaterialType } from './model/material.js'; +import { TextureMap, MaterialBase, FaceMaterial, PhongMaterial, PhysicalMaterial, TextureMapIsEqual, TextureIsEqual, MaterialType } from './model/material.js'; import { Mesh } from './model/mesh.js'; import { MeshPrimitiveBuffer, MeshBuffer, ConvertMeshToMeshBuffer } from './model/meshbuffer.js'; import { MeshInstanceId, MeshInstance } from './model/meshinstance.js'; @@ -230,7 +230,6 @@ export { Line, TextureMap, MaterialBase, - LineMaterial, FaceMaterial, PhongMaterial, PhysicalMaterial, diff --git a/source/engine/model/line.js b/source/engine/model/line.js index c753972..3eef13e 100644 --- a/source/engine/model/line.js +++ b/source/engine/model/line.js @@ -1,16 +1,14 @@ export class Line { - constructor (v0, v1) + constructor (vertices) { - this.v0 = v0; - this.v1 = v1; - + this.vertices = vertices; this.mat = null; } HasVertices () { - return this.v0 !== null && this.v1 !== null; + return this.vertices !== null && this.vertices.length >= 2; } SetMaterial (mat) @@ -21,7 +19,7 @@ export class Line Clone () { - let cloned = new Line (this.v0, this.v1); + let cloned = new Line ([...this.vertices]); cloned.SetMaterial (this.mat); return cloned; } diff --git a/source/engine/model/material.js b/source/engine/model/material.js index 50a1bb3..a77a19c 100644 --- a/source/engine/model/material.js +++ b/source/engine/model/material.js @@ -66,9 +66,8 @@ export function TextureMapIsEqual (aTex, bTex) export const MaterialType = { - Line : 1, - Phong : 2, - Physical : 3 + Phong : 1, + Physical : 2 }; export class MaterialBase @@ -105,14 +104,6 @@ export class MaterialBase } } -export class LineMaterial extends MaterialBase -{ - constructor (type) - { - super (MaterialType.Line); - } -} - export class FaceMaterial extends MaterialBase { constructor (type) diff --git a/source/engine/model/modelfinalization.js b/source/engine/model/modelfinalization.js index 04e68b4..c200cc0 100644 --- a/source/engine/model/modelfinalization.js +++ b/source/engine/model/modelfinalization.js @@ -1,9 +1,15 @@ import { CopyObjectAttributes } from '../core/core.js'; import { AddCoord3D, Coord3D, CoordIsEqual3D } from '../geometry/coord3d.js'; import { RGBColor } from './color.js'; -import { LineMaterial, PhongMaterial } from './material.js'; +import { PhongMaterial } from './material.js'; import { CalculateTriangleNormal, IsEmptyMesh } from './meshutils.js'; +const MaterialSource = +{ + Line : 1, + Face : 2 +}; + class ModelFinalizer { constructor (params) @@ -13,6 +19,7 @@ class ModelFinalizer defaultMaterialColor : new RGBColor (0, 0, 0) }; CopyObjectAttributes (params, this.params); + this.defaultLineMaterialIndex = null; this.defaultMaterialIndex = null; } @@ -141,7 +148,7 @@ class ModelFinalizer for (let i = 0; i < mesh.LineCount (); i++) { let line = mesh.GetLine (i); if (line.mat === null) { - line.mat = this.GetDefaultLineMaterialIndex (model); + line.mat = this.GetDefaultMaterialIndex (model, MaterialSource.Line); } } @@ -149,7 +156,7 @@ class ModelFinalizer let triangle = mesh.GetTriangle (i); this.FinalizeTriangle (mesh, triangle, meshStatus); if (triangle.mat === null) { - triangle.mat = this.GetDefaultMaterialIndex (model); + triangle.mat = this.GetDefaultMaterialIndex (model, MaterialSource.Face); } } @@ -202,26 +209,28 @@ class ModelFinalizer } } - GetDefaultLineMaterialIndex (model) + GetDefaultMaterialIndex (model, source) { - if (this.defaultLineMaterialIndex === null) { - let defaultMaterial = new LineMaterial (); - defaultMaterial.color = this.params.defaultLineMaterialColor; - defaultMaterial.isDefault = true; - this.defaultLineMaterialIndex = model.AddMaterial (defaultMaterial); - } - return this.defaultLineMaterialIndex; - } - - GetDefaultMaterialIndex (model) - { - if (this.defaultMaterialIndex === null) { + function GetIndex (model, index, color) + { + if (index !== null) { + return index; + } let defaultMaterial = new PhongMaterial (); - defaultMaterial.color = this.params.defaultMaterialColor; + defaultMaterial.color = color; defaultMaterial.isDefault = true; - this.defaultMaterialIndex = model.AddMaterial (defaultMaterial); + return model.AddMaterial (defaultMaterial); + } + + if (source === MaterialSource.Line) { + this.defaultLineMaterialIndex = GetIndex (model, this.defaultLineMaterialIndex, this.params.defaultLineMaterialColor) + return this.defaultLineMaterialIndex; + } else if (source === MaterialSource.Face) { + this.defaultMaterialIndex = GetIndex (model, this.defaultMaterialIndex, this.params.defaultMaterialColor); + return this.defaultMaterialIndex; + } else { + return null; } - return this.defaultMaterialIndex; } Reset () diff --git a/test/tests/mesh_test.js b/test/tests/mesh_test.js index df101b6..5dcc516 100644 --- a/test/tests/mesh_test.js +++ b/test/tests/mesh_test.js @@ -54,12 +54,12 @@ describe ('Mesh', function() { it ('Add Line', function () { var mesh = new OV.Mesh (); - var index = mesh.AddLine (new OV.Line (0, 1)); + var index = mesh.AddLine (new OV.Line ([0, 1])); assert.strictEqual (index, 0); assert.strictEqual (mesh.LineCount (), 1); var line = mesh.GetLine (index); - assert.strictEqual (line.v0, 0); - assert.strictEqual (line.v1, 1); + assert.strictEqual (line.vertices[0], 0); + assert.strictEqual (line.vertices[1], 1); }); it ('Add Triangle', function () { diff --git a/test/tests/model_test.js b/test/tests/model_test.js index 97857cb..90d0c2c 100644 --- a/test/tests/model_test.js +++ b/test/tests/model_test.js @@ -41,9 +41,9 @@ describe ('Model', function () { mesh.AddNormal (new OV.Coord3D (0.0, 0.0, 0.0)); mesh.AddNormal (new OV.Coord3D (0.0, 0.0, 0.0)); mesh.AddTextureUV (new OV.Coord2D (0.0, 0.0)); - mesh.AddLine (new OV.Line (0, 1)); - mesh.AddLine (new OV.Line (1, 2)); - mesh.AddLine (new OV.Line (2, 0)); + mesh.AddLine (new OV.Line ([0, 1])); + mesh.AddLine (new OV.Line ([1, 2])); + mesh.AddLine (new OV.Line ([2, 0])); mesh.AddTriangle (new OV.Triangle (0, 1, 2)); mesh.AddTriangle (new OV.Triangle (0, 1, 2)); mesh.AddTriangle (new OV.Triangle (0, 1, 2)); @@ -95,14 +95,20 @@ describe ('Model Finalization', function () { var v0 = mesh.AddVertex (new OV.Coord3D (0.0, 0.0, 0.0)); var v1 = mesh.AddVertex (new OV.Coord3D (1.0, 0.0, 0.0)); var v2 = mesh.AddVertex (new OV.Coord3D (1.0, 1.0, 0.0)); - mesh.AddLine (new OV.Line (v0, v1)); + var v3 = mesh.AddVertex (new OV.Coord3D (1.0, 1.0, 0.0)); + mesh.AddLine (new OV.Line ([v0, v1])); + mesh.AddLine (new OV.Line ([v1, v2])); mesh.AddTriangle (new OV.Triangle (v0, v1, v2)); + mesh.AddTriangle (new OV.Triangle (v0, v2, v3)); var model = new OV.Model (); model.AddMesh (mesh); - OV.FinalizeModel (model); + OV.FinalizeModel (model, { + defaultLineMaterialColor : new OV.RGBColor (1, 2, 3), + defaultMaterialColor : new OV.RGBColor (4, 5, 6) + }); assert.strictEqual (model.MaterialCount (), 2); - assert.strictEqual (model.GetMaterial (0).type, OV.MaterialType.Line); - assert.strictEqual (model.GetMaterial (1).type, OV.MaterialType.Phong); + assert.deepStrictEqual (model.GetMaterial (0).color, new OV.RGBColor (1, 2, 3)); + assert.deepStrictEqual (model.GetMaterial (1).color, new OV.RGBColor (4, 5, 6)); }); it ('Calculate Normal', function () { From aa984afbdbf53d6d63152304377cb3e8fb5c01d6 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 17 Oct 2023 18:13:31 +0200 Subject: [PATCH 04/29] Fix jshint error. --- source/engine/model/modelfinalization.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/engine/model/modelfinalization.js b/source/engine/model/modelfinalization.js index c200cc0..e9475eb 100644 --- a/source/engine/model/modelfinalization.js +++ b/source/engine/model/modelfinalization.js @@ -223,7 +223,7 @@ class ModelFinalizer } if (source === MaterialSource.Line) { - this.defaultLineMaterialIndex = GetIndex (model, this.defaultLineMaterialIndex, this.params.defaultLineMaterialColor) + this.defaultLineMaterialIndex = GetIndex (model, this.defaultLineMaterialIndex, this.params.defaultLineMaterialColor); return this.defaultLineMaterialIndex; } else if (source === MaterialSource.Face) { this.defaultMaterialIndex = GetIndex (model, this.defaultMaterialIndex, this.params.defaultMaterialColor); From 2db87713176f636b5874d2275549c7753461343d Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 17 Oct 2023 19:08:32 +0200 Subject: [PATCH 05/29] Rename function. --- source/engine/import/importerobj.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/engine/import/importerobj.js b/source/engine/import/importerobj.js index 0853567..845fcb8 100644 --- a/source/engine/import/importerobj.js +++ b/source/engine/import/importerobj.js @@ -22,28 +22,28 @@ class ObjMeshConverter AddVertex (globalIndex, globalVertices) { - return this.GetLocalIndex (globalIndex, globalVertices, this.globalToMeshVertices, (val) => { + return this.GetMeshIndex (globalIndex, globalVertices, this.globalToMeshVertices, (val) => { return this.mesh.AddVertex (new Coord3D (val.x, val.y, val.z)); }); } AddVertexColor (globalIndex, globalVertexColors) { - return this.GetLocalIndex (globalIndex, globalVertexColors, this.globalToMeshVertexColors, (val) => { + return this.GetMeshIndex (globalIndex, globalVertexColors, this.globalToMeshVertexColors, (val) => { return this.mesh.AddVertexColor (new RGBColor (val.r, val.g, val.b)); }); } AddNormal (globalIndex, globalNormals) { - return this.GetLocalIndex (globalIndex, globalNormals, this.globalToMeshNormals, (val) => { + return this.GetMeshIndex (globalIndex, globalNormals, this.globalToMeshNormals, (val) => { return this.mesh.AddNormal (new Coord3D (val.x, val.y, val.z)); }); } AddUV (globalIndex, globalUvs) { - return this.GetLocalIndex (globalIndex, globalUvs, this.globalToMeshUvs, (val) => { + return this.GetMeshIndex (globalIndex, globalUvs, this.globalToMeshUvs, (val) => { return this.mesh.AddTextureUV (new Coord2D (val.x, val.y)); }); } @@ -53,7 +53,7 @@ class ObjMeshConverter this.mesh.AddTriangle (triangle); } - GetLocalIndex (globalIndex, globalValueArray, globalToMeshIndices, valueAdderFunc) + GetMeshIndex (globalIndex, globalValueArray, globalToMeshIndices, valueAdderFunc) { if (isNaN (globalIndex) || globalIndex < 0 || globalIndex >= globalValueArray.length) { return null; @@ -62,9 +62,9 @@ class ObjMeshConverter return globalToMeshIndices.get (globalIndex); } else { let globalValue = globalValueArray[globalIndex]; - let localIndex = valueAdderFunc (globalValue); - globalToMeshIndices.set (globalIndex, localIndex); - return localIndex; + let meshIndex = valueAdderFunc (globalValue); + globalToMeshIndices.set (globalIndex, meshIndex); + return meshIndex; } } } From bfec1a2c04a978c1f95947fc4d4c090fff8c3ca6 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 17 Oct 2023 19:08:43 +0200 Subject: [PATCH 06/29] Add test files. --- test/testfiles/obj/lines.obj | 11 +++++++++ test/testfiles/obj/lines_colors.mtl | 14 +++++++++++ test/testfiles/obj/lines_colors.obj | 18 ++++++++++++++ test/testfiles/obj/lines_triangles_colors.mtl | 14 +++++++++++ test/testfiles/obj/lines_triangles_colors.obj | 24 +++++++++++++++++++ 5 files changed, 81 insertions(+) create mode 100644 test/testfiles/obj/lines.obj create mode 100644 test/testfiles/obj/lines_colors.mtl create mode 100644 test/testfiles/obj/lines_colors.obj create mode 100644 test/testfiles/obj/lines_triangles_colors.mtl create mode 100644 test/testfiles/obj/lines_triangles_colors.obj diff --git a/test/testfiles/obj/lines.obj b/test/testfiles/obj/lines.obj new file mode 100644 index 0000000..58f2e8b --- /dev/null +++ b/test/testfiles/obj/lines.obj @@ -0,0 +1,11 @@ +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 1.0 1.0 0.0 +v 0.0 1.0 0.0 +v 0.0 0.0 1.0 +v 1.0 0.0 1.0 +v 1.0 1.0 1.0 +v 0.0 1.0 1.0 +l 1 2 +l 3 4 +l 5 6 6 7 7 8 8 5 diff --git a/test/testfiles/obj/lines_colors.mtl b/test/testfiles/obj/lines_colors.mtl new file mode 100644 index 0000000..cd2c541 --- /dev/null +++ b/test/testfiles/obj/lines_colors.mtl @@ -0,0 +1,14 @@ +newmtl Red +Ka 0.000000 0.000000 0.000000 +Kd 0.800000 0.200000 0.200000 +Ks 0.500000 0.500000 0.500000 + +newmtl Green +Ka 0.000000 0.000000 0.000000 +Kd 0.152940 0.607840 0.380390 +Ks 0.500000 0.500000 0.500000 + +newmtl Blue +Ka 0.000000 0.000000 0.000000 +Kd 0.000000 0.541180 0.721570 +Ks 0.500000 0.500000 0.500000 diff --git a/test/testfiles/obj/lines_colors.obj b/test/testfiles/obj/lines_colors.obj new file mode 100644 index 0000000..9e55285 --- /dev/null +++ b/test/testfiles/obj/lines_colors.obj @@ -0,0 +1,18 @@ +mtllib lines_colors.mtl + +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 1.0 1.0 0.0 +v 0.0 1.0 0.0 +v 0.0 0.0 1.0 +v 1.0 0.0 1.0 +v 1.0 1.0 1.0 +v 0.0 1.0 1.0 +usemtl Red +l 1 2 +l 3 4 +usemtl Green +l 5 6 6 7 7 8 8 5 +usemtl Blue +l 1 5 + diff --git a/test/testfiles/obj/lines_triangles_colors.mtl b/test/testfiles/obj/lines_triangles_colors.mtl new file mode 100644 index 0000000..cd2c541 --- /dev/null +++ b/test/testfiles/obj/lines_triangles_colors.mtl @@ -0,0 +1,14 @@ +newmtl Red +Ka 0.000000 0.000000 0.000000 +Kd 0.800000 0.200000 0.200000 +Ks 0.500000 0.500000 0.500000 + +newmtl Green +Ka 0.000000 0.000000 0.000000 +Kd 0.152940 0.607840 0.380390 +Ks 0.500000 0.500000 0.500000 + +newmtl Blue +Ka 0.000000 0.000000 0.000000 +Kd 0.000000 0.541180 0.721570 +Ks 0.500000 0.500000 0.500000 diff --git a/test/testfiles/obj/lines_triangles_colors.obj b/test/testfiles/obj/lines_triangles_colors.obj new file mode 100644 index 0000000..cd5acad --- /dev/null +++ b/test/testfiles/obj/lines_triangles_colors.obj @@ -0,0 +1,24 @@ +mtllib lines_triangles_colors.mtl + +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 1.0 1.0 0.0 +v 0.0 1.0 0.0 +v 0.0 0.0 1.0 +v 1.0 0.0 1.0 +v 1.0 1.0 1.0 +v 0.0 1.0 1.0 +v 0.0 0.0 2.0 +v 1.0 0.0 2.0 +v 1.0 1.0 2.0 +v 0.0 1.0 2.0 +usemtl Red +l 1 2 +l 3 4 +f 9 10 11 +usemtl Green +l 5 6 6 7 7 8 8 5 +f 9 11 12 +usemtl Blue +l 1 5 +f 9 5 8 12 From 1af09bf377c953b9dc87889bf4ee7fb4bf02b3ea Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 17 Oct 2023 19:47:00 +0200 Subject: [PATCH 07/29] Read lines from obj files. --- source/engine/import/importerobj.js | 82 ++++++++++++++++++-------- test/tests/importerobj_test.js | 90 +++++++++++++++++++++++++++++ test/tests/importeroff_test.js | 8 +++ test/tests/importerply_test.js | 4 ++ test/tests/importerstl_test.js | 4 ++ test/utils/testutils.js | 20 ++++++- 6 files changed, 183 insertions(+), 25 deletions(-) diff --git a/source/engine/import/importerobj.js b/source/engine/import/importerobj.js index 845fcb8..b26dae9 100644 --- a/source/engine/import/importerobj.js +++ b/source/engine/import/importerobj.js @@ -2,6 +2,7 @@ import { Coord2D } from '../geometry/coord2d.js'; import { Coord3D } from '../geometry/coord3d.js'; import { Direction } from '../geometry/geometry.js'; import { ArrayBufferToUtf8String } from '../io/bufferutils.js'; +import { Line } from '../model/line.js'; import { RGBColor, RGBColorFromFloatComponents } from '../model/color.js'; import { PhongMaterial, TextureMap } from '../model/material.js'; import { Mesh } from '../model/mesh.js'; @@ -48,6 +49,11 @@ class ObjMeshConverter }); } + AddLine (line) + { + this.mesh.AddLine (line); + } + AddTriangle (triangle) { this.mesh.AddTriangle (triangle); @@ -213,11 +219,16 @@ export class ImporterObj extends ImporterBase parseFloat (parameters[1]) )); return true; + } else if (keyword === 'l') { + if (parameters.length < 2 || parameters.length % 2 !== 0) { + return true; + } + this.ProcessLineCommand (parameters); } else if (keyword === 'f') { if (parameters.length < 3) { return true; } - this.ProcessFace (parameters); + this.ProcessFaceCommand (parameters); return true; } @@ -375,40 +386,56 @@ export class ImporterObj extends ImporterBase return false; } - ProcessFace (parameters) + ProcessLineCommand (parameters) { - function GetRelativeIndex (index, count) - { - if (index > 0) { - return index - 1; - } else { - return count + index; - } + if (this.currentMeshConverter === null) { + this.AddNewMesh (''); } + let vertices = []; + for (let i = 0; i < parameters.length; i++) { + let vertexIndex = this.GetRelativeIndex (parseInt (parameters[i], 10), this.globalVertices.length); + let meshVertexIndex = this.currentMeshConverter.AddVertex (vertexIndex, this.globalVertices); + if (meshVertexIndex === null) { + this.SetError ('Invalid vertex index.'); + break; + } + vertices.push (meshVertexIndex); + } + + let line = new Line (vertices); + if (this.currentMaterialIndex !== null) { + line.mat = this.currentMaterialIndex; + } + + this.currentMeshConverter.AddLine (line); + } + + ProcessFaceCommand (parameters) + { let vertices = []; let colors = []; let normals = []; let uvs = []; - for (let i = 0; i < parameters.length; i++) { - let vertexParams = parameters[i].split ('/'); - vertices.push (GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length)); - if (this.globalVertices.length === this.globalVertexColors.length) { - colors.push (GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length)); - } - if (vertexParams.length > 1 && vertexParams[1].length > 0) { - uvs.push (GetRelativeIndex (parseInt (vertexParams[1], 10), this.globalUvs.length)); - } - if (vertexParams.length > 2 && vertexParams[2].length > 0) { - normals.push (GetRelativeIndex (parseInt (vertexParams[2], 10), this.globalNormals.length)); - } - } - if (this.currentMeshConverter === null) { this.AddNewMesh (''); } + for (let i = 0; i < parameters.length; i++) { + let vertexParams = parameters[i].split ('/'); + vertices.push (this.GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length)); + if (this.globalVertices.length === this.globalVertexColors.length) { + colors.push (this.GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length)); + } + if (vertexParams.length > 1 && vertexParams[1].length > 0) { + uvs.push (this.GetRelativeIndex (parseInt (vertexParams[1], 10), this.globalUvs.length)); + } + if (vertexParams.length > 2 && vertexParams[2].length > 0) { + normals.push (this.GetRelativeIndex (parseInt (vertexParams[2], 10), this.globalNormals.length)); + } + } + for (let i = 0; i < vertices.length - 2; i++) { let v0 = this.currentMeshConverter.AddVertex (vertices[0], this.globalVertices); let v1 = this.currentMeshConverter.AddVertex (vertices[i + 1], this.globalVertices); @@ -460,4 +487,13 @@ export class ImporterObj extends ImporterBase this.currentMeshConverter.AddTriangle (triangle); } } + + GetRelativeIndex (index, count) + { + if (index > 0) { + return index - 1; + } else { + return count + index; + } + } } diff --git a/test/tests/importerobj_test.js b/test/tests/importerobj_test.js index f565c05..cc89e9c 100644 --- a/test/tests/importerobj_test.js +++ b/test/tests/importerobj_test.js @@ -18,6 +18,7 @@ describe ('Obj Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -44,6 +45,7 @@ describe ('Obj Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -76,6 +78,7 @@ describe ('Obj Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -108,6 +111,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'MyMeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -134,6 +138,7 @@ describe ('Obj Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -160,6 +165,7 @@ describe ('Obj Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -186,6 +192,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'MeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -212,6 +219,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'MeshName1', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -223,6 +231,7 @@ describe ('Obj Importer', function () { }, { name : 'MeshName2', + lines : [], triangles : [ { vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], @@ -249,6 +258,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'MeshName1', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -260,6 +270,7 @@ describe ('Obj Importer', function () { }, { name : 'MeshName2', + lines : [], triangles : [ { vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1], @@ -287,6 +298,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'MeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -314,6 +326,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'MeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -346,6 +359,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'MeshName1', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -357,6 +371,7 @@ describe ('Obj Importer', function () { }, { name : 'MeshName2', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 0, 0, 1], @@ -383,6 +398,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'MeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -415,6 +431,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'Mesh', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -449,6 +466,7 @@ describe ('Obj Importer', function () { meshes : [ { name : 'Mesh', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -628,6 +646,78 @@ describe ('Obj Importer', function () { done (); }); }); + + it ('lines.obj', function (done) { + ImportObjFile ('lines.obj', function (model) { + assert.ok (OV.CheckModel (model)); + assert.deepStrictEqual (ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + lines : [ + { + vertices : [0, 0, 0, 1, 0, 0], + mat : 0 + }, + { + vertices : [1, 1, 0, 0, 1, 0], + mat : 0 + }, + { + vertices : [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1], + mat : 0 + } + ], + triangles : [] + } + ] + }); + done (); + }); + }); + + it ('lines_colors.obj', function (done) { + ImportObjFile ('lines_colors.obj', function (model) { + assert.ok (OV.CheckModel (model)); + assert.deepStrictEqual (ModelToObject (model), { + name : '', + materials : [ + { name : 'Red' }, + { name : 'Green' }, + { name : 'Blue' } + ], + meshes : [ + { + name : '', + lines : [ + { + vertices : [0, 0, 0, 1, 0, 0], + mat : 0 + }, + { + vertices : [1, 1, 0, 0, 1, 0], + mat : 0 + }, + { + vertices : [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1], + mat : 1 + }, + { + vertices : [0, 0, 0, 0, 0, 1], + mat : 2 + } + ], + triangles : [] + } + ] + }); + done (); + }); + }); }); } diff --git a/test/tests/importeroff_test.js b/test/tests/importeroff_test.js index 093330f..352f46d 100644 --- a/test/tests/importeroff_test.js +++ b/test/tests/importeroff_test.js @@ -18,6 +18,7 @@ describe ('Off Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -44,6 +45,7 @@ describe ('Off Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -76,6 +78,7 @@ describe ('Off Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -108,6 +111,7 @@ describe ('Off Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -162,6 +166,7 @@ describe ('Off Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -195,6 +200,7 @@ describe ('Off Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -229,6 +235,7 @@ describe ('Off Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -263,6 +270,7 @@ describe ('Off Importer', function () { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], diff --git a/test/tests/importerply_test.js b/test/tests/importerply_test.js index a5a6fd6..7e7e11d 100644 --- a/test/tests/importerply_test.js +++ b/test/tests/importerply_test.js @@ -18,6 +18,7 @@ describe ('Ply Importer', function() { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -44,6 +45,7 @@ describe ('Ply Importer', function() { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -76,6 +78,7 @@ describe ('Ply Importer', function() { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -108,6 +111,7 @@ describe ('Ply Importer', function() { meshes : [ { name : '', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], diff --git a/test/tests/importerstl_test.js b/test/tests/importerstl_test.js index 870dff0..ea28375 100644 --- a/test/tests/importerstl_test.js +++ b/test/tests/importerstl_test.js @@ -18,6 +18,7 @@ describe ('Stl Importer', function() { meshes : [ { name : 'MeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -44,6 +45,7 @@ describe ('Stl Importer', function() { meshes : [ { name : 'MeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -70,6 +72,7 @@ describe ('Stl Importer', function() { meshes : [ { name : 'MeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], @@ -96,6 +99,7 @@ describe ('Stl Importer', function() { meshes : [ { name : 'MeshName', + lines : [], triangles : [ { vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0], diff --git a/test/utils/testutils.js b/test/utils/testutils.js index 598d53b..b09b666 100644 --- a/test/utils/testutils.js +++ b/test/utils/testutils.js @@ -55,7 +55,7 @@ export function ModelToObject (model) meshes : [] }; - var i, j; + var i, j, k; var material; for (i = 0; i < model.MaterialCount (); i++) { @@ -65,13 +65,29 @@ export function ModelToObject (model) }); } - var mesh, triangle, meshObj, triangleObj; + var mesh, line, triangle, meshObj, lineObj, triangleObj; for (i = 0; i < model.MeshCount (); i++) { mesh = model.GetMesh (i); meshObj = { name : mesh.GetName (), + lines : [], triangles : [] }; + for (j = 0; j < mesh.LineCount (); j++) { + line = mesh.GetLine (j); + lineObj = { + mat : line.mat, + vertices : [] + }; + for (k = 0; k < line.vertices.length; k++) { + lineObj.vertices.push ( + mesh.GetVertex (line.vertices[k]).x, + mesh.GetVertex (line.vertices[k]).y, + mesh.GetVertex (line.vertices[k]).z + ); + } + meshObj.lines.push (lineObj); + } for (j = 0; j < mesh.TriangleCount (); j++) { triangle = mesh.GetTriangle (j); triangleObj = { From a3f9138579d33bf9652b3e90652a9de50d84c102 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 17 Oct 2023 19:56:41 +0200 Subject: [PATCH 08/29] Add test for lines in meshes. --- test/testfiles/obj/lines_in_meshes.obj | 13 +++++++++ test/tests/importerobj_test.js | 39 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 test/testfiles/obj/lines_in_meshes.obj diff --git a/test/testfiles/obj/lines_in_meshes.obj b/test/testfiles/obj/lines_in_meshes.obj new file mode 100644 index 0000000..2f52e8a --- /dev/null +++ b/test/testfiles/obj/lines_in_meshes.obj @@ -0,0 +1,13 @@ +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 1.0 1.0 0.0 +v 0.0 1.0 0.0 +v 0.0 0.0 1.0 +v 1.0 0.0 1.0 +v 1.0 1.0 1.0 +v 0.0 1.0 1.0 +g Mesh01 +l 1 2 +l 3 4 +g Mesh02 +l 5 6 6 7 7 8 8 5 diff --git a/test/tests/importerobj_test.js b/test/tests/importerobj_test.js index cc89e9c..5dea9ed 100644 --- a/test/tests/importerobj_test.js +++ b/test/tests/importerobj_test.js @@ -680,6 +680,45 @@ describe ('Obj Importer', function () { }); }); + it ('lines_in_meshes.obj', function (done) { + ImportObjFile ('lines_in_meshes.obj', function (model) { + assert.ok (OV.CheckModel (model)); + assert.deepStrictEqual (ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'Mesh01', + lines : [ + { + vertices : [0, 0, 0, 1, 0, 0], + mat : 0 + }, + { + vertices : [1, 1, 0, 0, 1, 0], + mat : 0 + } + ], + triangles : [] + }, + { + name : 'Mesh02', + lines : [ + { + vertices : [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1], + mat : 0 + } + ], + triangles : [] + } + ] + }); + done (); + }); + }); + it ('lines_colors.obj', function (done) { ImportObjFile ('lines_colors.obj', function (model) { assert.ok (OV.CheckModel (model)); From 0b925de4739d7e94f195cc894490f29c7d16df89 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 17 Oct 2023 19:58:32 +0200 Subject: [PATCH 09/29] Add another test. --- test/testfiles/obj/lines_in_meshes_2.obj | 16 ++++++++++ test/tests/importerobj_test.js | 39 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 test/testfiles/obj/lines_in_meshes_2.obj diff --git a/test/testfiles/obj/lines_in_meshes_2.obj b/test/testfiles/obj/lines_in_meshes_2.obj new file mode 100644 index 0000000..0f3cb25 --- /dev/null +++ b/test/testfiles/obj/lines_in_meshes_2.obj @@ -0,0 +1,16 @@ +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 1.0 1.0 0.0 +v 0.0 1.0 0.0 + +g Mesh01 +l 1 2 +l 3 4 + +v 0.0 0.0 1.0 +v 1.0 0.0 1.0 +v 1.0 1.0 1.0 +v 0.0 1.0 1.0 + +g Mesh02 +l 5 6 6 7 7 8 8 5 diff --git a/test/tests/importerobj_test.js b/test/tests/importerobj_test.js index 5dea9ed..bd372b5 100644 --- a/test/tests/importerobj_test.js +++ b/test/tests/importerobj_test.js @@ -719,6 +719,45 @@ describe ('Obj Importer', function () { }); }); + it ('lines_in_meshes_2.obj', function (done) { + ImportObjFile ('lines_in_meshes_2.obj', function (model) { + assert.ok (OV.CheckModel (model)); + assert.deepStrictEqual (ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : 'Mesh01', + lines : [ + { + vertices : [0, 0, 0, 1, 0, 0], + mat : 0 + }, + { + vertices : [1, 1, 0, 0, 1, 0], + mat : 0 + } + ], + triangles : [] + }, + { + name : 'Mesh02', + lines : [ + { + vertices : [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1], + mat : 0 + } + ], + triangles : [] + } + ] + }); + done (); + }); + }); + it ('lines_colors.obj', function (done) { ImportObjFile ('lines_colors.obj', function (model) { assert.ok (OV.CheckModel (model)); From 7420e4dfeb8fbf6a3e2316858af981773995e3ca Mon Sep 17 00:00:00 2001 From: Viktor Kovacs Date: Sat, 21 Oct 2023 08:46:54 +0200 Subject: [PATCH 10/29] Convert line segments with dummy material. --- source/engine/model/line.js | 5 + source/engine/threejs/threeconverter.js | 175 +++++++++++++++++++++++- source/engine/viewer/viewermodel.js | 2 + source/website/website.js | 17 +-- 4 files changed, 185 insertions(+), 14 deletions(-) diff --git a/source/engine/model/line.js b/source/engine/model/line.js index 3eef13e..e88a962 100644 --- a/source/engine/model/line.js +++ b/source/engine/model/line.js @@ -11,6 +11,11 @@ export class Line return this.vertices !== null && this.vertices.length >= 2; } + GetVertices () + { + return this.vertices; + } + SetMaterial (mat) { this.mat = mat; diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index a458209..e996d11 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -213,10 +213,13 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) return threeMaterial; } - function CreateThreeMesh (meshInstance, modelThreeMaterials) + function CreateThreeTriangleMesh (meshInstance, modelThreeMaterials) { let mesh = meshInstance.mesh; let triangleCount = mesh.TriangleCount (); + if (triangleCount === 0) { + return null; + } let triangleIndices = []; for (let i = 0; i < triangleCount; i++) { @@ -246,8 +249,7 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) let meshHasVertexColors = (mesh.VertexColorCount () > 0); let meshHasUVs = (mesh.TextureUVCount () > 0); - for (let i = 0; i < triangleIndices.length; i++) { - let triangleIndex = triangleIndices[i]; + for (let triangleIndex of triangleIndices) { let triangle = mesh.GetTriangle (triangleIndex); let v0 = mesh.GetVertex (triangle.v0); @@ -327,11 +329,172 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) return threeMesh; } + function CreateThreeLineMesh (meshInstance, modelThreeMaterials) + { + let mesh = meshInstance.mesh; + let lineCount = mesh.LineCount (); + if (lineCount === 0) { + return null; + } + + let lineIndices = []; + for (let i = 0; i < lineCount; i++) { + lineIndices.push (i); + } + lineIndices.sort ((a, b) => { + let aLine = mesh.GetLine (a); + let bLine = mesh.GetLine (b); + return aLine.mat - bLine.mat; + }); + + let vertices = []; + for (let lineIndex of lineIndices) { + let line = mesh.GetLine (lineIndex); + for (let vertexIndex of line.GetVertices ()) { + let vertex = mesh.GetVertex (vertexIndex); + vertices.push (vertex.x, vertex.y, vertex.z); + } + } + + let threeGeometry = new THREE.BufferGeometry (); + threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); + + const material = new THREE.LineBasicMaterial({ + color: 0x0000ff + }); + + let lineOriginalMaterials = [material]; + + let threeLine = new THREE.LineSegments (threeGeometry, material); + threeLine.userData = { + originalMeshInstance : meshInstance, + originalMaterials : lineOriginalMaterials, + threeMaterials : null + }; + return threeLine; + // let triangleIndices = []; + // for (let i = 0; i < triangleCount; i++) { + // triangleIndices.push (i); + // } + // triangleIndices.sort ((a, b) => { + // let aTriangle = mesh.GetTriangle (a); + // let bTriangle = mesh.GetTriangle (b); + // return aTriangle.mat - bTriangle.mat; + // }); + + // let threeGeometry = new THREE.BufferGeometry (); + // let meshThreeMaterials = []; + // let meshOriginalMaterials = []; + // let modelToThreeMaterials = new Map (); + + // let vertices = []; + // let vertexColors = []; + // let normals = []; + // let uvs = []; + + // let groups = []; + // groups.push ({ + // start : 0, + // end : -1 + // }); + + // let meshHasVertexColors = (mesh.VertexColorCount () > 0); + // let meshHasUVs = (mesh.TextureUVCount () > 0); + // for (let i = 0; i < triangleIndices.length; i++) { + // let triangleIndex = triangleIndices[i]; + // let triangle = mesh.GetTriangle (triangleIndex); + + // let v0 = mesh.GetVertex (triangle.v0); + // let v1 = mesh.GetVertex (triangle.v1); + // let v2 = mesh.GetVertex (triangle.v2); + // vertices.push (v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z); + + // if (triangle.HasVertexColors ()) { + // let vc0 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c0)); + // let vc1 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c1)); + // let vc2 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c2)); + // vertexColors.push ( + // vc0.r, vc0.g, vc0.b, + // vc1.r, vc1.g, vc1.b, + // vc2.r, vc2.g, vc2.b + // ); + // } else if (meshHasVertexColors) { + // vertexColors.push ( + // 0.0, 0.0, 0.0, + // 0.0, 0.0, 0.0, + // 0.0, 0.0, 0.0 + // ); + // } + + // let n0 = mesh.GetNormal (triangle.n0); + // let n1 = mesh.GetNormal (triangle.n1); + // let n2 = mesh.GetNormal (triangle.n2); + // normals.push (n0.x, n0.y, n0.z, n1.x, n1.y, n1.z, n2.x, n2.y, n2.z); + + // if (triangle.HasTextureUVs ()) { + // let u0 = mesh.GetTextureUV (triangle.u0); + // let u1 = mesh.GetTextureUV (triangle.u1); + // let u2 = mesh.GetTextureUV (triangle.u2); + // uvs.push (u0.x, u0.y, u1.x, u1.y, u2.x, u2.y); + // } else if (meshHasUVs) { + // uvs.push (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + // } + + // let modelMaterialIndex = triangle.mat; + // if (!modelToThreeMaterials.has (modelMaterialIndex)) { + // modelToThreeMaterials.set (modelMaterialIndex, meshThreeMaterials.length); + // meshThreeMaterials.push (modelThreeMaterials[modelMaterialIndex]); + // meshOriginalMaterials.push (modelMaterialIndex); + // if (i > 0) { + // groups[groups.length - 1].end = i - 1; + // groups.push ({ + // start : groups[groups.length - 1].end + 1, + // end : -1 + // }); + // } + // } + // } + + // groups[groups.length - 1].end = triangleCount - 1; + + // threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); + // if (vertexColors.length !== 0) { + // threeGeometry.setAttribute ('color', new THREE.Float32BufferAttribute (vertexColors, 3)); + // } + // threeGeometry.setAttribute ('normal', new THREE.Float32BufferAttribute (normals, 3)); + // if (uvs.length !== 0) { + // threeGeometry.setAttribute ('uv', new THREE.Float32BufferAttribute (uvs, 2)); + // } + // for (let i = 0; i < groups.length; i++) { + // let group = groups[i]; + // threeGeometry.addGroup (group.start * 3, (group.end - group.start + 1) * 3, i); + // } + + // let threeMesh = new THREE.Mesh (threeGeometry, meshThreeMaterials); + // threeMesh.name = mesh.GetName (); + // threeMesh.userData = { + // originalMeshInstance : meshInstance, + // originalMaterials : meshOriginalMaterials, + // threeMaterials : null + // }; + + // return threeMesh; + } + function ConvertMesh (threeObject, meshInstance, modelThreeMaterials) { - if (!IsEmptyMesh (meshInstance.mesh)) { - let threeMesh = CreateThreeMesh (meshInstance, modelThreeMaterials); - threeObject.add (threeMesh); + if (IsEmptyMesh (meshInstance.mesh)) { + return; + } + + let triangleMesh = CreateThreeTriangleMesh (meshInstance, modelThreeMaterials); + if (triangleMesh !== null) { + threeObject.add (triangleMesh); + } + + let lineMesh = CreateThreeLineMesh (meshInstance, modelThreeMaterials); + if (lineMesh !== null) { + threeObject.add (lineMesh); } } diff --git a/source/engine/viewer/viewermodel.js b/source/engine/viewer/viewermodel.js index e037210..5ad8c39 100644 --- a/source/engine/viewer/viewermodel.js +++ b/source/engine/viewer/viewermodel.js @@ -232,6 +232,8 @@ export class ViewerMainModel this.mainModel.Traverse ((obj) => { if (obj.isMesh) { enumerator (obj); + } else if (obj.type === 'LineSegments') { + enumerator (obj); } }); } diff --git a/source/website/website.js b/source/website/website.js index ec27178..89db998 100644 --- a/source/website/website.js +++ b/source/website/website.js @@ -836,15 +836,15 @@ export class Website InitNavigator () { - function GetMeshUserData (viewer, meshInstanceId) + function GetMeshUserDataArray (viewer, meshInstanceId) { - let userData = null; + let userDataArr = []; viewer.EnumerateMeshesUserData ((meshUserData) => { if (meshUserData.originalMeshInstance.id.IsEqual (meshInstanceId)) { - userData = meshUserData; + userDataArr.push (meshUserData); } }); - return userData; + return userDataArr; } function GetMeshesForMaterial (viewer, materialIndex) @@ -876,10 +876,11 @@ export class Website usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); } } else { - let userData = GetMeshUserData (viewer, meshInstanceId); - for (let i = 0; i < userData.originalMaterials.length; i++) { - const materialIndex = userData.originalMaterials[i]; - usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); + let userDataArr = GetMeshUserDataArray (viewer, meshInstanceId); + for (let userData of userDataArr) { + for (let materialIndex of userData.originalMaterials) { + usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); + } } } usedMaterials.sort ((a, b) => { From 077d46d1120fc16735b4bfbddc9766e2aefc8733 Mon Sep 17 00:00:00 2001 From: Viktor Kovacs Date: Sat, 21 Oct 2023 18:10:45 +0200 Subject: [PATCH 11/29] Refactor material conversion. --- source/engine/threejs/threeconverter.js | 253 ++++++++---------------- source/website/website.js | 5 + 2 files changed, 87 insertions(+), 171 deletions(-) diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index e996d11..37c1f78 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -97,50 +97,31 @@ export class ThreeNodeTree } } -export function ConvertModelToThreeObject (model, params, output, callbacks) +export class ThreeMaterialHandler { - function CreateThreeMaterial (stateHandler, model, materialIndex, shadingType, params, output) + constructor (model, stateHandler, conversionParams, conversionOutput) { - function SetTextureParameters (texture, threeTexture) - { - threeTexture.wrapS = THREE.RepeatWrapping; - threeTexture.wrapT = THREE.RepeatWrapping; - threeTexture.rotation = texture.rotation; - threeTexture.offset.x = texture.offset.x; - threeTexture.offset.y = texture.offset.y; - threeTexture.repeat.x = texture.scale.x; - threeTexture.repeat.y = texture.scale.y; - } + this.model = model; + this.stateHandler = stateHandler; + this.conversionParams = conversionParams; + this.conversionOutput = conversionOutput; - function LoadTexture (stateHandler, threeMaterial, texture, output, onTextureLoaded) - { - if (texture === null || !texture.IsValid ()) { - return; - } - let loader = new THREE.TextureLoader (); - stateHandler.OnTextureNeeded (); - let textureObjectUrl = null; - if (texture.mimeType !== null) { - textureObjectUrl = CreateObjectUrlWithMimeType (texture.buffer, texture.mimeType); - } else { - textureObjectUrl = CreateObjectUrl (texture.buffer); - } - output.objectUrls.push (textureObjectUrl); - loader.load (textureObjectUrl, - (threeTexture) => { - SetTextureParameters (texture, threeTexture); - threeMaterial.needsUpdate = true; - onTextureLoaded (threeTexture); - stateHandler.OnTextureLoaded (); - }, - null, - (err) => { - stateHandler.OnTextureLoaded (); - } - ); - } + this.shadingType = GetShadingType (model); + this.modelToThreeMaterial = new Map (); + } - let material = model.GetMaterial (materialIndex); + GetThreeMaterial (modelMaterialIndex) + { + if (!this.modelToThreeMaterial.has (modelMaterialIndex)) { + let threeMaterial = this.CreateThreeMaterial (modelMaterialIndex); + this.modelToThreeMaterial.set (modelMaterialIndex, threeMaterial); + } + return this.modelToThreeMaterial.get (modelMaterialIndex); + } + + CreateThreeMaterial (materialIndex) + { + let material = this.model.GetMaterial (materialIndex); let baseColor = ConvertColorToThreeColor (material.color); if (material.vertexColors) { baseColor.setRGB (1.0, 1.0, 1.0); @@ -155,12 +136,12 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) side : THREE.DoubleSide }; - if (params.forceMediumpForMaterials) { + if (this.conversionParams.forceMediumpForMaterials) { materialParams.precision = 'mediump'; } let threeMaterial = null; - if (shadingType === ShadingType.Phong) { + if (this.shadingType === ShadingType.Phong) { threeMaterial = new THREE.MeshPhongMaterial (materialParams); if (material.type === MaterialType.Phong) { let specularColor = ConvertColorToThreeColor (material.specular); @@ -169,16 +150,16 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) } threeMaterial.specular = specularColor; threeMaterial.shininess = material.shininess * 100.0; - LoadTexture (stateHandler, threeMaterial, material.specularMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.specularMap, (threeTexture) => { threeMaterial.specularMap = threeTexture; }); } - } else if (shadingType === ShadingType.Physical) { + } else if (this.shadingType === ShadingType.Physical) { threeMaterial = new THREE.MeshStandardMaterial (materialParams); if (material.type === MaterialType.Physical) { threeMaterial.metalness = material.metalness; threeMaterial.roughness = material.roughness; - LoadTexture (stateHandler, threeMaterial, material.metalnessMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.metalnessMap, (threeTexture) => { threeMaterial.metalness = 1.0; threeMaterial.roughness = 1.0; threeMaterial.metalnessMap = threeTexture; @@ -190,30 +171,72 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) let emissiveColor = ConvertColorToThreeColor (material.emissive); threeMaterial.emissive = emissiveColor; - LoadTexture (stateHandler, threeMaterial, material.diffuseMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.diffuseMap, (threeTexture) => { if (!material.multiplyDiffuseMap) { threeMaterial.color.setRGB (1.0, 1.0, 1.0); } threeMaterial.map = threeTexture; }); - LoadTexture (stateHandler, threeMaterial, material.bumpMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.bumpMap, (threeTexture) => { threeMaterial.bumpMap = threeTexture; }); - LoadTexture (stateHandler, threeMaterial, material.normalMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.normalMap, (threeTexture) => { threeMaterial.normalMap = threeTexture; }); - LoadTexture (stateHandler, threeMaterial, material.emissiveMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.emissiveMap, (threeTexture) => { threeMaterial.emissiveMap = threeTexture; }); if (material.isDefault) { - output.defaultMaterial = threeMaterial; + this.conversionOutput.defaultMaterial = threeMaterial; } return threeMaterial; } - function CreateThreeTriangleMesh (meshInstance, modelThreeMaterials) + LoadTexture (threeMaterial, texture, onTextureLoaded) + { + function SetTextureParameters (texture, threeTexture) + { + threeTexture.wrapS = THREE.RepeatWrapping; + threeTexture.wrapT = THREE.RepeatWrapping; + threeTexture.rotation = texture.rotation; + threeTexture.offset.x = texture.offset.x; + threeTexture.offset.y = texture.offset.y; + threeTexture.repeat.x = texture.scale.x; + threeTexture.repeat.y = texture.scale.y; + } + + if (texture === null || !texture.IsValid ()) { + return; + } + let loader = new THREE.TextureLoader (); + this.stateHandler.OnTextureNeeded (); + let textureObjectUrl = null; + if (texture.mimeType !== null) { + textureObjectUrl = CreateObjectUrlWithMimeType (texture.buffer, texture.mimeType); + } else { + textureObjectUrl = CreateObjectUrl (texture.buffer); + } + this.conversionOutput.objectUrls.push (textureObjectUrl); + loader.load (textureObjectUrl, + (threeTexture) => { + SetTextureParameters (texture, threeTexture); + threeMaterial.needsUpdate = true; + onTextureLoaded (threeTexture); + this.stateHandler.OnTextureLoaded (); + }, + null, + (err) => { + this.stateHandler.OnTextureLoaded (); + } + ); + } +} + +export function ConvertModelToThreeObject (model, conversionParams, conversionOutput, callbacks) +{ + function CreateThreeTriangleMesh (meshInstance, materialHandler) { let mesh = meshInstance.mesh; let triangleCount = mesh.TriangleCount (); @@ -249,7 +272,8 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) let meshHasVertexColors = (mesh.VertexColorCount () > 0); let meshHasUVs = (mesh.TextureUVCount () > 0); - for (let triangleIndex of triangleIndices) { + for (let i = 0; i < triangleIndices.length; i++) { + let triangleIndex = triangleIndices[i]; let triangle = mesh.GetTriangle (triangleIndex); let v0 = mesh.GetVertex (triangle.v0); @@ -290,8 +314,9 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) let modelMaterialIndex = triangle.mat; if (!modelToThreeMaterials.has (modelMaterialIndex)) { + let threeMaterial = materialHandler.GetThreeMaterial (modelMaterialIndex); modelToThreeMaterials.set (modelMaterialIndex, meshThreeMaterials.length); - meshThreeMaterials.push (modelThreeMaterials[modelMaterialIndex]); + meshThreeMaterials.push (threeMaterial); meshOriginalMaterials.push (modelMaterialIndex); if (i > 0) { groups[groups.length - 1].end = i - 1; @@ -372,113 +397,6 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) threeMaterials : null }; return threeLine; - // let triangleIndices = []; - // for (let i = 0; i < triangleCount; i++) { - // triangleIndices.push (i); - // } - // triangleIndices.sort ((a, b) => { - // let aTriangle = mesh.GetTriangle (a); - // let bTriangle = mesh.GetTriangle (b); - // return aTriangle.mat - bTriangle.mat; - // }); - - // let threeGeometry = new THREE.BufferGeometry (); - // let meshThreeMaterials = []; - // let meshOriginalMaterials = []; - // let modelToThreeMaterials = new Map (); - - // let vertices = []; - // let vertexColors = []; - // let normals = []; - // let uvs = []; - - // let groups = []; - // groups.push ({ - // start : 0, - // end : -1 - // }); - - // let meshHasVertexColors = (mesh.VertexColorCount () > 0); - // let meshHasUVs = (mesh.TextureUVCount () > 0); - // for (let i = 0; i < triangleIndices.length; i++) { - // let triangleIndex = triangleIndices[i]; - // let triangle = mesh.GetTriangle (triangleIndex); - - // let v0 = mesh.GetVertex (triangle.v0); - // let v1 = mesh.GetVertex (triangle.v1); - // let v2 = mesh.GetVertex (triangle.v2); - // vertices.push (v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z); - - // if (triangle.HasVertexColors ()) { - // let vc0 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c0)); - // let vc1 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c1)); - // let vc2 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c2)); - // vertexColors.push ( - // vc0.r, vc0.g, vc0.b, - // vc1.r, vc1.g, vc1.b, - // vc2.r, vc2.g, vc2.b - // ); - // } else if (meshHasVertexColors) { - // vertexColors.push ( - // 0.0, 0.0, 0.0, - // 0.0, 0.0, 0.0, - // 0.0, 0.0, 0.0 - // ); - // } - - // let n0 = mesh.GetNormal (triangle.n0); - // let n1 = mesh.GetNormal (triangle.n1); - // let n2 = mesh.GetNormal (triangle.n2); - // normals.push (n0.x, n0.y, n0.z, n1.x, n1.y, n1.z, n2.x, n2.y, n2.z); - - // if (triangle.HasTextureUVs ()) { - // let u0 = mesh.GetTextureUV (triangle.u0); - // let u1 = mesh.GetTextureUV (triangle.u1); - // let u2 = mesh.GetTextureUV (triangle.u2); - // uvs.push (u0.x, u0.y, u1.x, u1.y, u2.x, u2.y); - // } else if (meshHasUVs) { - // uvs.push (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); - // } - - // let modelMaterialIndex = triangle.mat; - // if (!modelToThreeMaterials.has (modelMaterialIndex)) { - // modelToThreeMaterials.set (modelMaterialIndex, meshThreeMaterials.length); - // meshThreeMaterials.push (modelThreeMaterials[modelMaterialIndex]); - // meshOriginalMaterials.push (modelMaterialIndex); - // if (i > 0) { - // groups[groups.length - 1].end = i - 1; - // groups.push ({ - // start : groups[groups.length - 1].end + 1, - // end : -1 - // }); - // } - // } - // } - - // groups[groups.length - 1].end = triangleCount - 1; - - // threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); - // if (vertexColors.length !== 0) { - // threeGeometry.setAttribute ('color', new THREE.Float32BufferAttribute (vertexColors, 3)); - // } - // threeGeometry.setAttribute ('normal', new THREE.Float32BufferAttribute (normals, 3)); - // if (uvs.length !== 0) { - // threeGeometry.setAttribute ('uv', new THREE.Float32BufferAttribute (uvs, 2)); - // } - // for (let i = 0; i < groups.length; i++) { - // let group = groups[i]; - // threeGeometry.addGroup (group.start * 3, (group.end - group.start + 1) * 3, i); - // } - - // let threeMesh = new THREE.Mesh (threeGeometry, meshThreeMaterials); - // threeMesh.name = mesh.GetName (); - // threeMesh.userData = { - // originalMeshInstance : meshInstance, - // originalMaterials : meshOriginalMaterials, - // threeMaterials : null - // }; - - // return threeMesh; } function ConvertMesh (threeObject, meshInstance, modelThreeMaterials) @@ -498,7 +416,7 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) } } - function ConvertNodeHierarchy (threeRootNode, model, modelThreeMaterials, stateHandler) + function ConvertNodeHierarchy (threeRootNode, model, materialHandler, stateHandler) { let nodeTree = new ThreeNodeTree (model, threeRootNode); let threeNodeItems = nodeTree.GetNodeItems (); @@ -507,7 +425,7 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) runTask : (firstMeshInstanceIndex, lastMeshInstanceIndex, onReady) => { for (let meshInstanceIndex = firstMeshInstanceIndex; meshInstanceIndex <= lastMeshInstanceIndex; meshInstanceIndex++) { let nodeItem = threeNodeItems[meshInstanceIndex]; - ConvertMesh (nodeItem.threeNode, nodeItem.meshInstance, modelThreeMaterials); + ConvertMesh (nodeItem.threeNode, nodeItem.meshInstance, materialHandler); } onReady (); }, @@ -518,14 +436,7 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) } let stateHandler = new ThreeConversionStateHandler (callbacks); - let shadingType = GetShadingType (model); - - let modelThreeMaterials = []; - for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) { - let threeMaterial = CreateThreeMaterial (stateHandler, model, materialIndex, shadingType, params, output); - modelThreeMaterials.push (threeMaterial); - } - + let materialHandler = new ThreeMaterialHandler (model, stateHandler, conversionParams, conversionOutput); let threeObject = new THREE.Object3D (); - ConvertNodeHierarchy (threeObject, model, modelThreeMaterials, stateHandler); + ConvertNodeHierarchy (threeObject, model, materialHandler, stateHandler); } diff --git a/source/website/website.js b/source/website/website.js index 89db998..1ad72cf 100644 --- a/source/website/website.js +++ b/source/website/website.js @@ -877,9 +877,14 @@ export class Website } } else { let userDataArr = GetMeshUserDataArray (viewer, meshInstanceId); + let addedMaterialIndices = new Set (); for (let userData of userDataArr) { for (let materialIndex of userData.originalMaterials) { + if (addedMaterialIndices.has (materialIndex)) { + continue; + } usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); + addedMaterialIndices.add (materialIndex); } } } From 1a4c3c128d2ca6d6cbf766761e18981b52288f2a Mon Sep 17 00:00:00 2001 From: Viktor Kovacs Date: Sun, 22 Oct 2023 18:08:30 +0200 Subject: [PATCH 12/29] Refactor mesh material handling. --- source/engine/threejs/threeconverter.js | 82 ++++++++++++++++--------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index 37c1f78..bf9f5d0 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -234,6 +234,52 @@ export class ThreeMaterialHandler } } +export class ThreeMeshMaterialHandler +{ + constructor (materialHandler) + { + this.materialHandler = materialHandler; + + this.meshThreeMaterials = []; + this.meshOriginalMaterials = []; + + this.groups = []; + this.previousMaterialIndex = null; + } + + ProcessItem (itemIndex, materialIndex) + { + if (this.previousMaterialIndex !== materialIndex) { + let threeMaterial = this.materialHandler.GetThreeMaterial (materialIndex); + this.meshThreeMaterials.push (threeMaterial); + this.meshOriginalMaterials.push (materialIndex); + + if (this.groups.length > 0) { + this.groups[this.groups.length - 1].end = itemIndex - 1; + } + this.groups.push ({ + start : itemIndex, + end : -1 + }); + + this.previousMaterialIndex = materialIndex; + } + } + + Finalize (triangleCount) + { + this.groups[this.groups.length - 1].end = triangleCount - 1; + } + + AddToGeometry (threeGeometry) + { + for (let materialIndex = 0; materialIndex < this.groups.length; materialIndex++) { + let group = this.groups[materialIndex]; + threeGeometry.addGroup (group.start * 3, (group.end - group.start + 1) * 3, materialIndex); + } + } +} + export function ConvertModelToThreeObject (model, conversionParams, conversionOutput, callbacks) { function CreateThreeTriangleMesh (meshInstance, materialHandler) @@ -255,21 +301,13 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu }); let threeGeometry = new THREE.BufferGeometry (); - let meshThreeMaterials = []; - let meshOriginalMaterials = []; - let modelToThreeMaterials = new Map (); + let meshMaterialHandler = new ThreeMeshMaterialHandler (materialHandler); let vertices = []; let vertexColors = []; let normals = []; let uvs = []; - let groups = []; - groups.push ({ - start : 0, - end : -1 - }); - let meshHasVertexColors = (mesh.VertexColorCount () > 0); let meshHasUVs = (mesh.TextureUVCount () > 0); for (let i = 0; i < triangleIndices.length; i++) { @@ -312,23 +350,11 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu uvs.push (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); } - let modelMaterialIndex = triangle.mat; - if (!modelToThreeMaterials.has (modelMaterialIndex)) { - let threeMaterial = materialHandler.GetThreeMaterial (modelMaterialIndex); - modelToThreeMaterials.set (modelMaterialIndex, meshThreeMaterials.length); - meshThreeMaterials.push (threeMaterial); - meshOriginalMaterials.push (modelMaterialIndex); - if (i > 0) { - groups[groups.length - 1].end = i - 1; - groups.push ({ - start : groups[groups.length - 1].end + 1, - end : -1 - }); - } - } + meshMaterialHandler.ProcessItem (i, triangle.mat); } - groups[groups.length - 1].end = triangleCount - 1; + meshMaterialHandler.Finalize (triangleCount); + meshMaterialHandler.AddToGeometry (threeGeometry); threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); if (vertexColors.length !== 0) { @@ -338,16 +364,12 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu if (uvs.length !== 0) { threeGeometry.setAttribute ('uv', new THREE.Float32BufferAttribute (uvs, 2)); } - for (let i = 0; i < groups.length; i++) { - let group = groups[i]; - threeGeometry.addGroup (group.start * 3, (group.end - group.start + 1) * 3, i); - } - let threeMesh = new THREE.Mesh (threeGeometry, meshThreeMaterials); + let threeMesh = new THREE.Mesh (threeGeometry, meshMaterialHandler.meshThreeMaterials); threeMesh.name = mesh.GetName (); threeMesh.userData = { originalMeshInstance : meshInstance, - originalMaterials : meshOriginalMaterials, + originalMaterials : meshMaterialHandler.meshOriginalMaterials, threeMaterials : null }; From 757703a8895fbe02e3ddbcf9377b5e8d52bf98e8 Mon Sep 17 00:00:00 2001 From: Viktor Kovacs Date: Sun, 22 Oct 2023 18:11:18 +0200 Subject: [PATCH 13/29] Minor modifications. --- source/engine/threejs/threeconverter.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index bf9f5d0..174af5b 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -376,7 +376,7 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu return threeMesh; } - function CreateThreeLineMesh (meshInstance, modelThreeMaterials) + function CreateThreeLineMesh (meshInstance, materialHandler) { let mesh = meshInstance.mesh; let lineCount = mesh.LineCount (); @@ -421,18 +421,18 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu return threeLine; } - function ConvertMesh (threeObject, meshInstance, modelThreeMaterials) + function ConvertMesh (threeObject, meshInstance, materialHandler) { if (IsEmptyMesh (meshInstance.mesh)) { return; } - let triangleMesh = CreateThreeTriangleMesh (meshInstance, modelThreeMaterials); + let triangleMesh = CreateThreeTriangleMesh (meshInstance, materialHandler); if (triangleMesh !== null) { threeObject.add (triangleMesh); } - let lineMesh = CreateThreeLineMesh (meshInstance, modelThreeMaterials); + let lineMesh = CreateThreeLineMesh (meshInstance, materialHandler); if (lineMesh !== null) { threeObject.add (lineMesh); } From 474d46968bca9cdb6e9956c623f6ac18e2dc4f3f Mon Sep 17 00:00:00 2001 From: Viktor Kovacs Date: Sun, 22 Oct 2023 18:13:33 +0200 Subject: [PATCH 14/29] Minor modifications. --- source/engine/threejs/threeconverter.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index 174af5b..2628bdc 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -271,7 +271,7 @@ export class ThreeMeshMaterialHandler this.groups[this.groups.length - 1].end = triangleCount - 1; } - AddToGeometry (threeGeometry) + AddGroups (threeGeometry) { for (let materialIndex = 0; materialIndex < this.groups.length; materialIndex++) { let group = this.groups[materialIndex]; @@ -300,7 +300,6 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu return aTriangle.mat - bTriangle.mat; }); - let threeGeometry = new THREE.BufferGeometry (); let meshMaterialHandler = new ThreeMeshMaterialHandler (materialHandler); let vertices = []; @@ -352,10 +351,9 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu meshMaterialHandler.ProcessItem (i, triangle.mat); } - meshMaterialHandler.Finalize (triangleCount); - meshMaterialHandler.AddToGeometry (threeGeometry); + let threeGeometry = new THREE.BufferGeometry (); threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); if (vertexColors.length !== 0) { threeGeometry.setAttribute ('color', new THREE.Float32BufferAttribute (vertexColors, 3)); @@ -364,6 +362,7 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu if (uvs.length !== 0) { threeGeometry.setAttribute ('uv', new THREE.Float32BufferAttribute (uvs, 2)); } + meshMaterialHandler.AddGroups (threeGeometry); let threeMesh = new THREE.Mesh (threeGeometry, meshMaterialHandler.meshThreeMaterials); threeMesh.name = mesh.GetName (); @@ -406,7 +405,7 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu let threeGeometry = new THREE.BufferGeometry (); threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); - const material = new THREE.LineBasicMaterial({ + const material = new THREE.LineBasicMaterial ({ color: 0x0000ff }); From 97e7be473202e7ef9bb5c96392e96d80de83a533 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 08:46:34 +0200 Subject: [PATCH 15/29] Refactor mesh material handler. --- source/engine/main.js | 4 ++- source/engine/threejs/threeconverter.js | 33 +++++++++++-------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/source/engine/main.js b/source/engine/main.js index 3ef9349..f10c482 100644 --- a/source/engine/main.js +++ b/source/engine/main.js @@ -63,7 +63,7 @@ import { TopologyVertex, TopologyEdge, TopologyTriangleEdge, TopologyTriangle, T import { Triangle } from './model/triangle.js'; import { Unit } from './model/unit.js'; import { ParameterListBuilder, ParameterListParser, CreateUrlBuilder, CreateUrlParser, CreateModelUrlParameters, ParameterConverter } from './parameters/parameterlist.js'; -import { ModelToThreeConversionParams, ModelToThreeConversionOutput, ThreeConversionStateHandler, ThreeNodeTree, ConvertModelToThreeObject } from './threejs/threeconverter.js'; +import { ModelToThreeConversionParams, ModelToThreeConversionOutput, ThreeConversionStateHandler, ThreeNodeTree, ThreeMaterialHandler, ThreeMeshMaterialHandler, ConvertModelToThreeObject } from './threejs/threeconverter.js'; import { ThreeModelLoader } from './threejs/threemodelloader.js'; import { ThreeColorConverter, ThreeLinearToSRGBColorConverter, ThreeSRGBToLinearColorConverter, HasHighpDriverIssue, GetShadingType, ConvertThreeColorToColor, ConvertColorToThreeColor, ConvertThreeGeometryToMesh, DisposeThreeObjects, ShadingType } from './threejs/threeutils.js'; import { Camera, CameraIsEqual3D, NavigationMode, ProjectionMode } from './viewer/camera.js'; @@ -283,6 +283,8 @@ export { ModelToThreeConversionOutput, ThreeConversionStateHandler, ThreeNodeTree, + ThreeMaterialHandler, + ThreeMeshMaterialHandler, ConvertModelToThreeObject, ThreeModelLoader, ThreeColorConverter, diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index 2628bdc..9186b16 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -236,47 +236,43 @@ export class ThreeMaterialHandler export class ThreeMeshMaterialHandler { - constructor (materialHandler) + constructor (threeGeometry, materialHandler) { + this.threeGeometry = threeGeometry; this.materialHandler = materialHandler; this.meshThreeMaterials = []; this.meshOriginalMaterials = []; - this.groups = []; + this.groupStart = null; this.previousMaterialIndex = null; } ProcessItem (itemIndex, materialIndex) { if (this.previousMaterialIndex !== materialIndex) { + if (this.groupStart !== null) { + this.AddGroup (this.groupStart, itemIndex - 1); + } + this.groupStart = itemIndex; + let threeMaterial = this.materialHandler.GetThreeMaterial (materialIndex); this.meshThreeMaterials.push (threeMaterial); this.meshOriginalMaterials.push (materialIndex); - if (this.groups.length > 0) { - this.groups[this.groups.length - 1].end = itemIndex - 1; - } - this.groups.push ({ - start : itemIndex, - end : -1 - }); - this.previousMaterialIndex = materialIndex; } } Finalize (triangleCount) { - this.groups[this.groups.length - 1].end = triangleCount - 1; + this.AddGroup (this.groupStart, triangleCount - 1); } - AddGroups (threeGeometry) + AddGroup (start, end) { - for (let materialIndex = 0; materialIndex < this.groups.length; materialIndex++) { - let group = this.groups[materialIndex]; - threeGeometry.addGroup (group.start * 3, (group.end - group.start + 1) * 3, materialIndex); - } + let materialIndex = this.meshThreeMaterials.length - 1; + this.threeGeometry.addGroup (start * 3, (end - start + 1) * 3, materialIndex); } } @@ -300,7 +296,8 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu return aTriangle.mat - bTriangle.mat; }); - let meshMaterialHandler = new ThreeMeshMaterialHandler (materialHandler); + let threeGeometry = new THREE.BufferGeometry (); + let meshMaterialHandler = new ThreeMeshMaterialHandler (threeGeometry, materialHandler); let vertices = []; let vertexColors = []; @@ -353,7 +350,6 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu } meshMaterialHandler.Finalize (triangleCount); - let threeGeometry = new THREE.BufferGeometry (); threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); if (vertexColors.length !== 0) { threeGeometry.setAttribute ('color', new THREE.Float32BufferAttribute (vertexColors, 3)); @@ -362,7 +358,6 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu if (uvs.length !== 0) { threeGeometry.setAttribute ('uv', new THREE.Float32BufferAttribute (uvs, 2)); } - meshMaterialHandler.AddGroups (threeGeometry); let threeMesh = new THREE.Mesh (threeGeometry, meshMaterialHandler.meshThreeMaterials); threeMesh.name = mesh.GetName (); From 0f3e42be4bee47b113fd2efef5b47ce4d34f7f3d Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 09:36:58 +0200 Subject: [PATCH 16/29] Add material groups to lines. --- source/engine/threejs/threeconverter.js | 118 +++++++++++++++++------- 1 file changed, 83 insertions(+), 35 deletions(-) diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index 9186b16..9a113b0 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -97,6 +97,12 @@ export class ThreeNodeTree } } +export const MaterialGeometryType = +{ + Line : 1, + Face : 2 +}; + export class ThreeMaterialHandler { constructor (model, stateHandler, conversionParams, conversionOutput) @@ -107,19 +113,30 @@ export class ThreeMaterialHandler this.conversionOutput = conversionOutput; this.shadingType = GetShadingType (model); + this.modelToThreeLineMaterial = new Map (); this.modelToThreeMaterial = new Map (); } - GetThreeMaterial (modelMaterialIndex) + GetThreeMaterial (modelMaterialIndex, geometryType) { - if (!this.modelToThreeMaterial.has (modelMaterialIndex)) { - let threeMaterial = this.CreateThreeMaterial (modelMaterialIndex); - this.modelToThreeMaterial.set (modelMaterialIndex, threeMaterial); + if (geometryType === MaterialGeometryType.Face) { + if (!this.modelToThreeMaterial.has (modelMaterialIndex)) { + let threeMaterial = this.CreateThreeFaceMaterial (modelMaterialIndex); + this.modelToThreeMaterial.set (modelMaterialIndex, threeMaterial); + } + return this.modelToThreeMaterial.get (modelMaterialIndex); + } else if (geometryType === MaterialGeometryType.Line) { + if (!this.modelToThreeLineMaterial.has (modelMaterialIndex)) { + let threeMaterial = this.CreateThreeLineMaterial (modelMaterialIndex); + this.modelToThreeLineMaterial.set (modelMaterialIndex, threeMaterial); + } + return this.modelToThreeLineMaterial.get (modelMaterialIndex); + } else { + return null; } - return this.modelToThreeMaterial.get (modelMaterialIndex); } - CreateThreeMaterial (materialIndex) + CreateThreeFaceMaterial (materialIndex) { let material = this.model.GetMaterial (materialIndex); let baseColor = ConvertColorToThreeColor (material.color); @@ -150,7 +167,7 @@ export class ThreeMaterialHandler } threeMaterial.specular = specularColor; threeMaterial.shininess = material.shininess * 100.0; - this.LoadTexture (threeMaterial, material.specularMap, (threeTexture) => { + this.LoadFaceTexture (threeMaterial, material.specularMap, (threeTexture) => { threeMaterial.specularMap = threeTexture; }); } @@ -159,7 +176,7 @@ export class ThreeMaterialHandler if (material.type === MaterialType.Physical) { threeMaterial.metalness = material.metalness; threeMaterial.roughness = material.roughness; - this.LoadTexture (threeMaterial, material.metalnessMap, (threeTexture) => { + this.LoadFaceTexture (threeMaterial, material.metalnessMap, (threeTexture) => { threeMaterial.metalness = 1.0; threeMaterial.roughness = 1.0; threeMaterial.metalnessMap = threeTexture; @@ -171,19 +188,19 @@ export class ThreeMaterialHandler let emissiveColor = ConvertColorToThreeColor (material.emissive); threeMaterial.emissive = emissiveColor; - this.LoadTexture (threeMaterial, material.diffuseMap, (threeTexture) => { + this.LoadFaceTexture (threeMaterial, material.diffuseMap, (threeTexture) => { if (!material.multiplyDiffuseMap) { threeMaterial.color.setRGB (1.0, 1.0, 1.0); } threeMaterial.map = threeTexture; }); - this.LoadTexture (threeMaterial, material.bumpMap, (threeTexture) => { + this.LoadFaceTexture (threeMaterial, material.bumpMap, (threeTexture) => { threeMaterial.bumpMap = threeTexture; }); - this.LoadTexture (threeMaterial, material.normalMap, (threeTexture) => { + this.LoadFaceTexture (threeMaterial, material.normalMap, (threeTexture) => { threeMaterial.normalMap = threeTexture; }); - this.LoadTexture (threeMaterial, material.emissiveMap, (threeTexture) => { + this.LoadFaceTexture (threeMaterial, material.emissiveMap, (threeTexture) => { threeMaterial.emissiveMap = threeTexture; }); @@ -194,7 +211,28 @@ export class ThreeMaterialHandler return threeMaterial; } - LoadTexture (threeMaterial, texture, onTextureLoaded) + CreateThreeLineMaterial (materialIndex) + { + let material = this.model.GetMaterial (materialIndex); + let baseColor = ConvertColorToThreeColor (material.color); + let materialParams = { + color : baseColor, + opacity : material.opacity + }; + + if (this.conversionParams.forceMediumpForMaterials) { + materialParams.precision = 'mediump'; + } + + let threeMaterial = new THREE.LineBasicMaterial (materialParams); + if (material.isDefault) { + this.conversionOutput.defaultMaterial = threeMaterial; + } + + return threeMaterial; + } + + LoadFaceTexture (threeMaterial, texture, onTextureLoaded) { function SetTextureParameters (texture, threeTexture) { @@ -236,11 +274,19 @@ export class ThreeMaterialHandler export class ThreeMeshMaterialHandler { - constructor (threeGeometry, materialHandler) + constructor (threeGeometry, geometryType, materialHandler) { this.threeGeometry = threeGeometry; + this.geometryType = geometryType; this.materialHandler = materialHandler; + this.itemVertexCount = null; + if (geometryType === MaterialGeometryType.Face) { + this.itemVertexCount = 3; + } else if (geometryType === MaterialGeometryType.Line) { + this.itemVertexCount = 2; + } + this.meshThreeMaterials = []; this.meshOriginalMaterials = []; @@ -256,7 +302,7 @@ export class ThreeMeshMaterialHandler } this.groupStart = itemIndex; - let threeMaterial = this.materialHandler.GetThreeMaterial (materialIndex); + let threeMaterial = this.materialHandler.GetThreeMaterial (materialIndex, this.geometryType); this.meshThreeMaterials.push (threeMaterial); this.meshOriginalMaterials.push (materialIndex); @@ -264,15 +310,15 @@ export class ThreeMeshMaterialHandler } } - Finalize (triangleCount) + Finalize (itemCount) { - this.AddGroup (this.groupStart, triangleCount - 1); + this.AddGroup (this.groupStart, itemCount - 1); } AddGroup (start, end) { let materialIndex = this.meshThreeMaterials.length - 1; - this.threeGeometry.addGroup (start * 3, (end - start + 1) * 3, materialIndex); + this.threeGeometry.addGroup (start * this.itemVertexCount, (end - start + 1) * this.itemVertexCount, materialIndex); } } @@ -297,7 +343,7 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu }); let threeGeometry = new THREE.BufferGeometry (); - let meshMaterialHandler = new ThreeMeshMaterialHandler (threeGeometry, materialHandler); + let meshMaterialHandler = new ThreeMeshMaterialHandler (threeGeometry, MaterialGeometryType.Face, materialHandler); let vertices = []; let vertexColors = []; @@ -306,8 +352,8 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu let meshHasVertexColors = (mesh.VertexColorCount () > 0); let meshHasUVs = (mesh.TextureUVCount () > 0); - for (let i = 0; i < triangleIndices.length; i++) { - let triangleIndex = triangleIndices[i]; + let processedTriangleCount = 0; + for (let triangleIndex of triangleIndices) { let triangle = mesh.GetTriangle (triangleIndex); let v0 = mesh.GetVertex (triangle.v0); @@ -346,9 +392,10 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu uvs.push (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); } - meshMaterialHandler.ProcessItem (i, triangle.mat); + meshMaterialHandler.ProcessItem (processedTriangleCount, triangle.mat); + processedTriangleCount += 1; } - meshMaterialHandler.Finalize (triangleCount); + meshMaterialHandler.Finalize (processedTriangleCount); threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); if (vertexColors.length !== 0) { @@ -388,28 +435,29 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu return aLine.mat - bLine.mat; }); + let threeGeometry = new THREE.BufferGeometry (); + let meshMaterialHandler = new ThreeMeshMaterialHandler (threeGeometry, MaterialGeometryType.Line, materialHandler); + let vertices = []; - for (let lineIndex of lineIndices) { - let line = mesh.GetLine (lineIndex); - for (let vertexIndex of line.GetVertices ()) { + let segmentCount = 0; + for (let i = 0; i < lineIndices.length; i++) { + let line = mesh.GetLine (lineIndices[i]); + let lineVertices = line.GetVertices (); + for (let vertexIndex of lineVertices) { let vertex = mesh.GetVertex (vertexIndex); vertices.push (vertex.x, vertex.y, vertex.z); } + meshMaterialHandler.ProcessItem (segmentCount, line.mat); + segmentCount += lineVertices.length / 2; } + meshMaterialHandler.Finalize (segmentCount); - let threeGeometry = new THREE.BufferGeometry (); threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); - const material = new THREE.LineBasicMaterial ({ - color: 0x0000ff - }); - - let lineOriginalMaterials = [material]; - - let threeLine = new THREE.LineSegments (threeGeometry, material); + let threeLine = new THREE.LineSegments (threeGeometry, meshMaterialHandler.meshThreeMaterials); threeLine.userData = { originalMeshInstance : meshInstance, - originalMaterials : lineOriginalMaterials, + originalMaterials : meshMaterialHandler.meshOriginalMaterials, threeMaterials : null }; return threeLine; From 4f0336c268870d42e7105638561803094472a950 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 11:40:18 +0200 Subject: [PATCH 17/29] Implement polygon offset if the model contains lines. --- source/engine/main.js | 11 ++-- source/engine/model/modelutils.js | 2 +- source/engine/threejs/threeconverter.js | 18 +++--- source/engine/threejs/threemodelloader.js | 18 +++--- source/engine/threejs/threeutils.js | 42 +++++++++++++ source/engine/viewer/shadingmodel.js | 24 +------- source/engine/viewer/viewer.js | 29 +++------ source/engine/viewer/viewermodel.js | 59 +++++++++++++++--- source/website/website.js | 18 +++--- test/testfiles/obj/cube_with_edges.mtl | 14 +++++ test/testfiles/obj/cube_with_edges.obj | 44 ++++++++++++++ test/testfiles/obj/lines_triangles_colors.obj | 60 +++++++++++++------ 12 files changed, 240 insertions(+), 99 deletions(-) create mode 100644 test/testfiles/obj/cube_with_edges.mtl create mode 100644 test/testfiles/obj/cube_with_edges.obj diff --git a/source/engine/main.js b/source/engine/main.js index f10c482..4dc7308 100644 --- a/source/engine/main.js +++ b/source/engine/main.js @@ -54,7 +54,7 @@ import { MeshInstanceId, MeshInstance } from './model/meshinstance.js'; import { IsEmptyMesh, CalculateTriangleNormal, TransformMesh, FlipMeshTrianglesOrientation } from './model/meshutils.js'; import { Model } from './model/model.js'; import { FinalizeModel, CheckModel } from './model/modelfinalization.js'; -import { IsModelEmpty, GetBoundingBox, GetTopology, IsTwoManifold, HasDefaultMaterial, ReplaceDefaultMaterialColor } from './model/modelutils.js'; +import { IsModelEmpty, GetBoundingBox, GetTopology, IsTwoManifold, HasDefaultMaterial, ReplaceDefaultMaterialsColor } from './model/modelutils.js'; import { Node } from './model/node.js'; import { Object3D, ModelObject3D } from './model/object.js'; import { Property, PropertyGroup, PropertyToString, PropertyType } from './model/property.js'; @@ -63,9 +63,9 @@ import { TopologyVertex, TopologyEdge, TopologyTriangleEdge, TopologyTriangle, T import { Triangle } from './model/triangle.js'; import { Unit } from './model/unit.js'; import { ParameterListBuilder, ParameterListParser, CreateUrlBuilder, CreateUrlParser, CreateModelUrlParameters, ParameterConverter } from './parameters/parameterlist.js'; -import { ModelToThreeConversionParams, ModelToThreeConversionOutput, ThreeConversionStateHandler, ThreeNodeTree, ThreeMaterialHandler, ThreeMeshMaterialHandler, ConvertModelToThreeObject } from './threejs/threeconverter.js'; +import { ModelToThreeConversionParams, ModelToThreeConversionOutput, ThreeConversionStateHandler, ThreeNodeTree, ThreeMaterialHandler, ThreeMeshMaterialHandler, ConvertModelToThreeObject, MaterialGeometryType } from './threejs/threeconverter.js'; import { ThreeModelLoader } from './threejs/threemodelloader.js'; -import { ThreeColorConverter, ThreeLinearToSRGBColorConverter, ThreeSRGBToLinearColorConverter, HasHighpDriverIssue, GetShadingType, ConvertThreeColorToColor, ConvertColorToThreeColor, ConvertThreeGeometryToMesh, DisposeThreeObjects, ShadingType } from './threejs/threeutils.js'; +import { ThreeColorConverter, ThreeLinearToSRGBColorConverter, ThreeSRGBToLinearColorConverter, HasHighpDriverIssue, GetShadingType, ConvertThreeColorToColor, ConvertColorToThreeColor, ConvertThreeGeometryToMesh, CreateHighlightMaterial, CreateHighlightMaterials, DisposeThreeObjects, ShadingType } from './threejs/threeutils.js'; import { Camera, CameraIsEqual3D, NavigationMode, ProjectionMode } from './viewer/camera.js'; import { GetIntegerFromStyle, GetDomElementExternalWidth, GetDomElementExternalHeight, GetDomElementInnerDimensions, GetDomElementClientCoordinates, CreateDomElement, AddDomElement, AddDiv, ClearDomElement, InsertDomElementBefore, InsertDomElementAfter, ShowDomElement, IsDomElementVisible, SetDomElementWidth, SetDomElementHeight, GetDomElementOuterWidth, GetDomElementOuterHeight, SetDomElementOuterWidth, SetDomElementOuterHeight, CreateDiv } from './viewer/domutils.js'; import { EmbeddedViewer, Init3DViewerFromUrlList, Init3DViewerFromFileList, Init3DViewerElements } from './viewer/embeddedviewer.js'; @@ -254,7 +254,7 @@ export { GetTopology, IsTwoManifold, HasDefaultMaterial, - ReplaceDefaultMaterialColor, + ReplaceDefaultMaterialsColor, Node, Object3D, ModelObject3D, @@ -286,6 +286,7 @@ export { ThreeMaterialHandler, ThreeMeshMaterialHandler, ConvertModelToThreeObject, + MaterialGeometryType, ThreeModelLoader, ThreeColorConverter, ThreeLinearToSRGBColorConverter, @@ -295,6 +296,8 @@ export { ConvertThreeColorToColor, ConvertColorToThreeColor, ConvertThreeGeometryToMesh, + CreateHighlightMaterial, + CreateHighlightMaterials, DisposeThreeObjects, ShadingType, Camera, diff --git a/source/engine/model/modelutils.js b/source/engine/model/modelutils.js index 064ba3e..8bb131d 100644 --- a/source/engine/model/modelutils.js +++ b/source/engine/model/modelutils.js @@ -106,7 +106,7 @@ export function HasDefaultMaterial (model) return false; } -export function ReplaceDefaultMaterialColor (model, color) +export function ReplaceDefaultMaterialsColor (model, color) { for (let i = 0; i < model.MaterialCount (); i++) { let material = model.GetMaterial (i); diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index 9a113b0..1625eb2 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -8,6 +8,12 @@ import { ConvertColorToThreeColor, GetShadingType, ShadingType } from './threeut import * as THREE from 'three'; +export const MaterialGeometryType = +{ + Line : 1, + Face : 2 +}; + export class ModelToThreeConversionParams { constructor () @@ -20,7 +26,7 @@ export class ModelToThreeConversionOutput { constructor () { - this.defaultMaterial = null; + this.defaultMaterials = []; this.objectUrls = []; } } @@ -97,12 +103,6 @@ export class ThreeNodeTree } } -export const MaterialGeometryType = -{ - Line : 1, - Face : 2 -}; - export class ThreeMaterialHandler { constructor (model, stateHandler, conversionParams, conversionOutput) @@ -205,7 +205,7 @@ export class ThreeMaterialHandler }); if (material.isDefault) { - this.conversionOutput.defaultMaterial = threeMaterial; + this.conversionOutput.defaultMaterials.push (threeMaterial); } return threeMaterial; @@ -226,7 +226,7 @@ export class ThreeMaterialHandler let threeMaterial = new THREE.LineBasicMaterial (materialParams); if (material.isDefault) { - this.conversionOutput.defaultMaterial = threeMaterial; + this.conversionOutput.defaultMaterials.push (threeMaterial); } return threeMaterial; diff --git a/source/engine/threejs/threemodelloader.js b/source/engine/threejs/threemodelloader.js index 73037a6..7be28f6 100644 --- a/source/engine/threejs/threemodelloader.js +++ b/source/engine/threejs/threemodelloader.js @@ -12,7 +12,7 @@ export class ThreeModelLoader { this.importer = new Importer (); this.inProgress = false; - this.defaultMaterial = null; + this.defaultMaterials = null; this.objectUrls = null; this.hasHighpDriverIssue = HasHighpDriverIssue (); } @@ -60,7 +60,7 @@ export class ThreeModelLoader callbacks.onTextureLoaded (); }, onModelLoaded : (threeObject) => { - this.defaultMaterial = output.defaultMaterial; + this.defaultMaterials = output.defaultMaterials; this.objectUrls = output.objectUrls; if (importResult.upVector === Direction.X) { let rotation = new THREE.Quaternion ().setFromAxisAngle (new THREE.Vector3 (0.0, 0.0, 1.0), Math.PI / 2.0); @@ -86,15 +86,19 @@ export class ThreeModelLoader return this.importer; } - GetDefaultMaterial () + GetDefaultMaterials () { - return this.defaultMaterial; + return this.defaultMaterials; } - ReplaceDefaultMaterialColor (defaultColor) + ReplaceDefaultMaterialsColor (defaultColor) { - if (this.defaultMaterial !== null && !this.defaultMaterial.vertexColors) { - this.defaultMaterial.color = ConvertColorToThreeColor (defaultColor); + if (this.defaultMaterials !== null) { + for (let defaultMaterial of this.defaultMaterials) { + if (!defaultMaterial.vertexColors) { + defaultMaterial.color = ConvertColorToThreeColor (defaultColor); + } + } } } diff --git a/source/engine/threejs/threeutils.js b/source/engine/threejs/threeutils.js index 928850c..132373b 100644 --- a/source/engine/threejs/threeutils.js +++ b/source/engine/threejs/threeutils.js @@ -210,6 +210,48 @@ export function ConvertThreeGeometryToMesh (threeGeometry, materialIndex, colorC return mesh; } +export function CreateHighlightMaterial (originalMaterial, highlightColor, withPolygonOffset) +{ + let material = null; + if (originalMaterial.type === 'MeshPhongMaterial') { + material = new THREE.MeshPhongMaterial ({ + color : ConvertColorToThreeColor (highlightColor), + side : THREE.DoubleSide + }); + } else if (originalMaterial.type === 'MeshStandardMaterial') { + material = new THREE.MeshStandardMaterial ({ + color : ConvertColorToThreeColor (highlightColor), + side : THREE.DoubleSide + }); + } else if (originalMaterial.type === 'LineBasicMaterial') { + material = new THREE.LineBasicMaterial ({ + color : ConvertColorToThreeColor (highlightColor) + }); + } + if (material !== null && withPolygonOffset) { + material.polygonOffset = true; + material.polygonOffsetUnit = 1; + material.polygonOffsetFactor = 1; + } + return material; +} + +export function CreateHighlightMaterials (originalMaterials, highlightColor, withPolygonOffset) +{ + let typeToHighlightMaterial = new Map (); + let highlightMaterials = []; + for (let originalMaterial of originalMaterials) { + if (typeToHighlightMaterial.has (originalMaterial.type)) { + highlightMaterials.push (typeToHighlightMaterial.get (originalMaterial.type)); + continue; + } + let highlightMaterial = CreateHighlightMaterial (originalMaterial, highlightColor, withPolygonOffset); + typeToHighlightMaterial.set (originalMaterial.type, highlightMaterial); + highlightMaterials.push (highlightMaterial); + } + return highlightMaterials; +} + export function DisposeThreeObjects (mainObject) { if (mainObject === null) { diff --git a/source/engine/viewer/shadingmodel.js b/source/engine/viewer/shadingmodel.js index 8fa5c16..d732261 100644 --- a/source/engine/viewer/shadingmodel.js +++ b/source/engine/viewer/shadingmodel.js @@ -1,6 +1,6 @@ import { SubCoord3D } from '../geometry/coord3d.js'; import { ProjectionMode } from '../viewer/camera.js'; -import { ConvertColorToThreeColor, ShadingType } from '../threejs/threeutils.js'; +import { ShadingType } from '../threejs/threeutils.js'; import * as THREE from 'three'; @@ -99,26 +99,4 @@ export class ShadingModel const lightDir = SubCoord3D (camera.eye, camera.center); this.directionalLight.position.set (lightDir.x, lightDir.y, lightDir.z); } - - CreateHighlightMaterial (highlightColor, withOffset) - { - let material = null; - if (this.type === ShadingType.Phong) { - material = new THREE.MeshPhongMaterial ({ - color : ConvertColorToThreeColor (highlightColor), - side : THREE.DoubleSide - }); - } else if (this.type === ShadingType.Physical) { - material = new THREE.MeshStandardMaterial ({ - color : ConvertColorToThreeColor (highlightColor), - side : THREE.DoubleSide - }); - } - if (material !== null && withOffset) { - material.polygonOffset = true; - material.polygonOffsetUnit = 1; - material.polygonOffsetFactor = 1; - } - return material; - } } diff --git a/source/engine/viewer/viewer.js b/source/engine/viewer/viewer.js index 7d64115..8bd7c51 100644 --- a/source/engine/viewer/viewer.js +++ b/source/engine/viewer/viewer.js @@ -1,7 +1,7 @@ import { Coord3D, CoordDistance3D, SubCoord3D } from '../geometry/coord3d.js'; import { DegRad, Direction, IsEqual } from '../geometry/geometry.js'; import { ColorComponentToFloat } from '../model/color.js'; -import { ShadingType } from '../threejs/threeutils.js'; +import { CreateHighlightMaterials, ShadingType } from '../threejs/threeutils.js'; import { Camera, NavigationMode, ProjectionMode } from './camera.js'; import { GetDomElementInnerDimensions } from './domutils.js'; import { Navigation } from './navigation.js'; @@ -448,7 +448,7 @@ export class Viewer SetMeshesVisibility (isVisible) { - this.mainModel.EnumerateMeshes ((mesh) => { + this.mainModel.EnumerateMeshesAndLines ((mesh) => { let visible = isVisible (mesh.userData); if (mesh.visible !== visible) { mesh.visible = visible; @@ -465,22 +465,13 @@ export class Viewer SetMeshesHighlight (highlightColor, isHighlighted) { - function CreateHighlightMaterials (originalMaterials, highlightMaterial) - { - let highlightMaterials = []; - for (let i = 0; i < originalMaterials.length; i++) { - highlightMaterials.push (highlightMaterial); - } - return highlightMaterials; - } - - const highlightMaterial = this.CreateHighlightMaterial (highlightColor); - this.mainModel.EnumerateMeshes ((mesh) => { + let withPolygonOffset = this.mainModel.HasLinesOrEdges (); + this.mainModel.EnumerateMeshesAndLines ((mesh) => { let highlighted = isHighlighted (mesh.userData); if (highlighted) { if (mesh.userData.threeMaterials === null) { mesh.userData.threeMaterials = mesh.material; - mesh.material = CreateHighlightMaterials (mesh.material, highlightMaterial); + mesh.material = CreateHighlightMaterials (mesh.userData.threeMaterials, highlightColor, withPolygonOffset); } } else { if (mesh.userData.threeMaterials !== null) { @@ -493,12 +484,6 @@ export class Viewer this.Render (); } - CreateHighlightMaterial (highlightColor) - { - const showEdges = this.mainModel.edgeSettings.showEdges; - return this.shadingModel.CreateHighlightMaterial (highlightColor, showEdges); - } - GetMeshUserDataUnderMouse (mouseCoords) { let intersection = this.GetMeshIntersectionUnderMouse (mouseCoords); @@ -528,9 +513,9 @@ export class Viewer return this.mainModel.GetBoundingSphere (needToProcess); } - EnumerateMeshesUserData (enumerator) + EnumerateMeshesAndLinesUserData (enumerator) { - this.mainModel.EnumerateMeshes ((mesh) => { + this.mainModel.EnumerateMeshesAndLines ((mesh) => { enumerator (mesh.userData); }); } diff --git a/source/engine/viewer/viewermodel.js b/source/engine/viewer/viewermodel.js index 5ad8c39..15c8781 100644 --- a/source/engine/viewer/viewermodel.js +++ b/source/engine/viewer/viewermodel.js @@ -119,14 +119,24 @@ export class ViewerMainModel this.edgeModel = new ViewerModel (this.scene); this.edgeSettings = new EdgeSettings (false, new RGBColor (0, 0, 0), 1); + this.hasLines = false; + this.hasPolygonOffset = false; } SetMainObject (mainObject) { this.mainModel.SetRootObject (mainObject); + this.hasLines = false; + this.hasPolygonOffset = false; + + this.EnumerateLines ((line) => { + this.hasLines = true; + }); + if (this.edgeSettings.showEdges) { this.GenerateEdgeModel (); } + this.UpdatePolygonOffset (); } UpdateWorldMatrix () @@ -169,7 +179,6 @@ export class ViewerMainModel this.UpdateWorldMatrix (); this.EnumerateMeshes ((mesh) => { - SetThreeMeshPolygonOffset (mesh, true); let edges = new THREE.EdgesGeometry (mesh.geometry, this.edgeSettings.edgeThreshold); let line = new THREE.LineSegments (edges, new THREE.LineBasicMaterial ({ color: edgeColor @@ -179,13 +188,15 @@ export class ViewerMainModel line.visible = mesh.visible; this.edgeModel.AddObject (line); }); + + this.UpdatePolygonOffset (); } GetBoundingBox (needToProcess) { let hasMesh = false; let boundingBox = new THREE.Box3 (); - this.EnumerateMeshes ((mesh) => { + this.EnumerateMeshesAndLines ((mesh) => { if (needToProcess (mesh.userData)) { boundingBox.union (new THREE.Box3 ().setFromObject (mesh)); hasMesh = true; @@ -221,9 +232,7 @@ export class ViewerMainModel return; } - this.EnumerateMeshes ((mesh) => { - SetThreeMeshPolygonOffset (mesh, false); - }); + this.UpdatePolygonOffset (); this.edgeModel.Clear (); } @@ -232,7 +241,25 @@ export class ViewerMainModel this.mainModel.Traverse ((obj) => { if (obj.isMesh) { enumerator (obj); - } else if (obj.type === 'LineSegments') { + } + }); + } + + EnumerateLines (enumerator) + { + this.mainModel.Traverse ((obj) => { + if (obj.isLineSegments) { + enumerator (obj); + } + }); + } + + EnumerateMeshesAndLines (enumerator) + { + this.mainModel.Traverse ((obj) => { + if (obj.isMesh) { + enumerator (obj); + } else if (obj.isLineSegments) { enumerator (obj); } }); @@ -247,6 +274,22 @@ export class ViewerMainModel }); } + HasLinesOrEdges () + { + return this.hasLines || this.edgeSettings.showEdges; + } + + UpdatePolygonOffset () + { + let needPolygonOffset = this.HasLinesOrEdges (); + if (needPolygonOffset !== this.hasPolygonOffset) { + this.EnumerateMeshes ((mesh) => { + SetThreeMeshPolygonOffset (mesh, needPolygonOffset); + }); + this.hasPolygonOffset = needPolygonOffset; + } + } + GetMeshIntersectionUnderMouse (mouseCoords, camera, width, height) { if (this.mainModel.IsEmpty ()) { @@ -258,6 +301,8 @@ export class ViewerMainModel } let raycaster = new THREE.Raycaster (); + raycaster.params.Line.threshold = 0.1; + let mousePos = new THREE.Vector2 (); mousePos.x = (mouseCoords.x / width) * 2 - 1; mousePos.y = -(mouseCoords.y / height) * 2 + 1; @@ -265,7 +310,7 @@ export class ViewerMainModel let iSectObjects = raycaster.intersectObject (this.mainModel.GetRootObject (), true); for (let i = 0; i < iSectObjects.length; i++) { let iSectObject = iSectObjects[i]; - if (iSectObject.object.isMesh && iSectObject.object.visible) { + if ((iSectObject.object.isMesh || iSectObject.object.isLineSegments) && iSectObject.object.visible) { return iSectObject; } } diff --git a/source/website/website.js b/source/website/website.js index 1ad72cf..38016bc 100644 --- a/source/website/website.js +++ b/source/website/website.js @@ -19,7 +19,7 @@ import { ShowSnapshotDialog } from './snapshotdialog.js'; import { AddSvgIconElement, GetFilesFromDataTransfer, InstallTooltip, IsSmallWidth } from './utils.js'; import { ShowOpenUrlDialog } from './openurldialog.js'; import { ShowSharingDialog } from './sharingdialog.js'; -import { HasDefaultMaterial, ReplaceDefaultMaterialColor } from '../engine/model/modelutils.js'; +import { HasDefaultMaterial, ReplaceDefaultMaterialsColor } from '../engine/model/modelutils.js'; import { Direction } from '../engine/geometry/geometry.js'; import { CookieGetBoolVal, CookieSetBoolVal } from './cookiehandler.js'; import { MeasureTool } from './measuretool.js'; @@ -577,9 +577,9 @@ export class Website this.viewer.SetBackgroundColor (this.settings.backgroundColor); let modelLoader = this.modelLoaderUI.GetModelLoader (); - if (modelLoader.GetDefaultMaterial () !== null) { - ReplaceDefaultMaterialColor (this.model, this.settings.defaultColor); - modelLoader.ReplaceDefaultMaterialColor (this.settings.defaultColor); + if (modelLoader.GetDefaultMaterials () !== null) { + ReplaceDefaultMaterialsColor (this.model, this.settings.defaultColor); + modelLoader.ReplaceDefaultMaterialsColor (this.settings.defaultColor); } } @@ -814,9 +814,9 @@ export class Website onDefaultColorChanged : () => { this.settings.SaveToCookies (); let modelLoader = this.modelLoaderUI.GetModelLoader (); - if (modelLoader.GetDefaultMaterial () !== null) { - ReplaceDefaultMaterialColor (this.model, this.settings.defaultColor); - modelLoader.ReplaceDefaultMaterialColor (this.settings.defaultColor); + if (modelLoader.GetDefaultMaterials () !== null) { + ReplaceDefaultMaterialsColor (this.model, this.settings.defaultColor); + modelLoader.ReplaceDefaultMaterialsColor (this.settings.defaultColor); } this.viewer.Render (); }, @@ -839,7 +839,7 @@ export class Website function GetMeshUserDataArray (viewer, meshInstanceId) { let userDataArr = []; - viewer.EnumerateMeshesUserData ((meshUserData) => { + viewer.EnumerateMeshesAndLinesUserData ((meshUserData) => { if (meshUserData.originalMeshInstance.id.IsEqual (meshInstanceId)) { userDataArr.push (meshUserData); } @@ -850,7 +850,7 @@ export class Website function GetMeshesForMaterial (viewer, materialIndex) { let usedByMeshes = []; - viewer.EnumerateMeshesUserData ((meshUserData) => { + viewer.EnumerateMeshesAndLinesUserData ((meshUserData) => { if (materialIndex === null || meshUserData.originalMaterials.indexOf (materialIndex) !== -1) { usedByMeshes.push (meshUserData.originalMeshInstance); } diff --git a/test/testfiles/obj/cube_with_edges.mtl b/test/testfiles/obj/cube_with_edges.mtl new file mode 100644 index 0000000..edd0bee --- /dev/null +++ b/test/testfiles/obj/cube_with_edges.mtl @@ -0,0 +1,14 @@ +newmtl Red +Ka 0.000000 0.000000 0.000000 +Kd 0.800000 0.000000 0.000000 +Ks 0.500000 0.500000 0.500000 + +newmtl Green +Ka 0.000000 0.000000 0.000000 +Kd 0.000000 0.800000 0.000000 +Ks 0.500000 0.500000 0.500000 + +newmtl Blue +Ka 0.000000 0.000000 0.000000 +Kd 0.000000 0.000000 0.800000 +Ks 0.500000 0.500000 0.500000 diff --git a/test/testfiles/obj/cube_with_edges.obj b/test/testfiles/obj/cube_with_edges.obj new file mode 100644 index 0000000..bdfdb79 --- /dev/null +++ b/test/testfiles/obj/cube_with_edges.obj @@ -0,0 +1,44 @@ +# Cube with Materials + +mtllib cube_with_edges.mtl + +g Cube + +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 1.0 1.0 0.0 +v 0.0 1.0 0.0 +v 0.0 0.0 1.0 +v 1.0 0.0 1.0 +v 1.0 1.0 1.0 +v 0.0 1.0 1.0 + +vn 1.0 0.0 0.0 +vn -1.0 0.0 0.0 +vn 0.0 1.0 0.0 +vn 0.0 -1.0 0.0 +vn 0.0 0.0 1.0 +vn 0.0 0.0 -1.0 + +vt 0.0 0.0 +vt 1.0 0.0 +vt 1.0 1.0 +vt 0.0 1.0 + +f 1/1/6 4/2/6 3/3/6 2/4/6 +f 2/1/1 3/2/1 7/3/1 6/4/1 +f 4/1/2 1/2/2 5/3/2 8/4/2 +f 5/1/5 6/2/5 7/3/5 8/4/5 + +l 1 4 2 3 6 7 5 8 + +usemtl Red +f 3/1/3 4/2/3 8/3/3 7/4/3 + +usemtl Blue +f 1/1/4 2/2/4 6/3/4 5/4/4 + +usemtl Green +l 3 4 4 8 8 7 7 3 +l 1 2 2 6 6 5 5 1 + diff --git a/test/testfiles/obj/lines_triangles_colors.obj b/test/testfiles/obj/lines_triangles_colors.obj index cd5acad..93a8ca3 100644 --- a/test/testfiles/obj/lines_triangles_colors.obj +++ b/test/testfiles/obj/lines_triangles_colors.obj @@ -2,23 +2,49 @@ mtllib lines_triangles_colors.mtl v 0.0 0.0 0.0 v 1.0 0.0 0.0 -v 1.0 1.0 0.0 -v 0.0 1.0 0.0 -v 0.0 0.0 1.0 v 1.0 0.0 1.0 -v 1.0 1.0 1.0 -v 0.0 1.0 1.0 -v 0.0 0.0 2.0 -v 1.0 0.0 2.0 -v 1.0 1.0 2.0 -v 0.0 1.0 2.0 +v 0.0 0.0 1.0 +v 0.5 1.0 0.5 + +g Mesh01 usemtl Red -l 1 2 -l 3 4 -f 9 10 11 -usemtl Green -l 5 6 6 7 7 8 8 5 -f 9 11 12 -usemtl Blue +f 1 2 3 l 1 5 -f 9 5 8 12 +usemtl Green +f 1 3 4 +l 3 5 + +v 2.0 0.0 0.0 +v 3.0 0.0 0.0 +v 3.0 0.0 1.0 +v 2.0 0.0 1.0 +v 2.5 1.0 0.5 + +g Mesh02 +usemtl Red +f 6 7 8 +l 6 10 +usemtl Green +f 6 8 9 +l 8 10 + +v 4.0 0.0 0.0 +v 5.0 0.0 0.0 +v 5.0 0.0 1.0 +v 4.0 0.0 1.0 + +g Mesh03 +usemtl Red +f 11 12 13 +usemtl Green +f 11 13 14 + +v 6.0 0.0 0.0 +v 7.0 0.0 1.0 +v 6.5 1.0 0.5 + +g Mesh04 +usemtl Red +l 15 17 +usemtl Green +l 16 17 From 978b1dfd197ce2635d29d5087a85d89ce39a4312 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 12:17:03 +0200 Subject: [PATCH 18/29] Introduce material source parameter to distinguish materials created for lines and faces. --- source/engine/model/material.js | 11 +++++++++-- source/engine/model/modelfinalization.js | 24 +++++++++-------------- source/engine/model/modelutils.js | 5 +++-- source/engine/threejs/threeconverter.js | 8 +++++--- source/engine/threejs/threemodelloader.js | 3 ++- source/website/sidebardetailspanel.js | 5 +++-- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/source/engine/model/material.js b/source/engine/model/material.js index a77a19c..1fa4404 100644 --- a/source/engine/model/material.js +++ b/source/engine/model/material.js @@ -70,12 +70,19 @@ export const MaterialType = Physical : 2 }; +export const MaterialSource = +{ + Model : 1, + DefaultFace : 2, + DefaultLine : 3 +}; + export class MaterialBase { constructor (type) { this.type = type; - this.isDefault = false; + this.source = MaterialSource.Model; this.name = ''; this.color = new RGBColor (0, 0, 0); @@ -88,7 +95,7 @@ export class MaterialBase if (this.type !== rhs.type) { return false; } - if (this.isDefault !== rhs.isDefault) { + if (this.source !== rhs.source) { return false; } if (this.name !== rhs.name) { diff --git a/source/engine/model/modelfinalization.js b/source/engine/model/modelfinalization.js index e9475eb..97cac35 100644 --- a/source/engine/model/modelfinalization.js +++ b/source/engine/model/modelfinalization.js @@ -1,15 +1,9 @@ import { CopyObjectAttributes } from '../core/core.js'; import { AddCoord3D, Coord3D, CoordIsEqual3D } from '../geometry/coord3d.js'; import { RGBColor } from './color.js'; -import { PhongMaterial } from './material.js'; +import { MaterialSource, PhongMaterial } from './material.js'; import { CalculateTriangleNormal, IsEmptyMesh } from './meshutils.js'; -const MaterialSource = -{ - Line : 1, - Face : 2 -}; - class ModelFinalizer { constructor (params) @@ -148,7 +142,7 @@ class ModelFinalizer for (let i = 0; i < mesh.LineCount (); i++) { let line = mesh.GetLine (i); if (line.mat === null) { - line.mat = this.GetDefaultMaterialIndex (model, MaterialSource.Line); + line.mat = this.GetDefaultMaterialIndex (model, MaterialSource.DefaultLine); } } @@ -156,7 +150,7 @@ class ModelFinalizer let triangle = mesh.GetTriangle (i); this.FinalizeTriangle (mesh, triangle, meshStatus); if (triangle.mat === null) { - triangle.mat = this.GetDefaultMaterialIndex (model, MaterialSource.Face); + triangle.mat = this.GetDefaultMaterialIndex (model, MaterialSource.DefaultFace); } } @@ -211,22 +205,22 @@ class ModelFinalizer GetDefaultMaterialIndex (model, source) { - function GetIndex (model, index, color) + function GetIndex (model, index, source, color) { if (index !== null) { return index; } let defaultMaterial = new PhongMaterial (); defaultMaterial.color = color; - defaultMaterial.isDefault = true; + defaultMaterial.source = source; return model.AddMaterial (defaultMaterial); } - if (source === MaterialSource.Line) { - this.defaultLineMaterialIndex = GetIndex (model, this.defaultLineMaterialIndex, this.params.defaultLineMaterialColor); + if (source === MaterialSource.DefaultLine) { + this.defaultLineMaterialIndex = GetIndex (model, this.defaultLineMaterialIndex, MaterialSource.DefaultLine, this.params.defaultLineMaterialColor); return this.defaultLineMaterialIndex; - } else if (source === MaterialSource.Face) { - this.defaultMaterialIndex = GetIndex (model, this.defaultMaterialIndex, this.params.defaultMaterialColor); + } else if (source === MaterialSource.DefaultFace) { + this.defaultMaterialIndex = GetIndex (model, this.defaultMaterialIndex, MaterialSource.DefaultFace, this.params.defaultMaterialColor); return this.defaultMaterialIndex; } else { return null; diff --git a/source/engine/model/modelutils.js b/source/engine/model/modelutils.js index 8bb131d..70724b1 100644 --- a/source/engine/model/modelutils.js +++ b/source/engine/model/modelutils.js @@ -1,5 +1,6 @@ import { BoundingBoxCalculator3D } from '../geometry/box3d.js'; import { Octree } from '../geometry/octree.js'; +import { MaterialSource } from './material.js'; import { IsEmptyMesh } from './meshutils.js'; import { Model } from './model.js'; import { Topology } from './topology.js'; @@ -99,7 +100,7 @@ export function HasDefaultMaterial (model) { for (let i = 0; i < model.MaterialCount (); i++) { let material = model.GetMaterial (i); - if (material.isDefault && !material.vertexColors) { + if (material.source !== MaterialSource.Model && !material.vertexColors) { return true; } } @@ -110,7 +111,7 @@ export function ReplaceDefaultMaterialsColor (model, color) { for (let i = 0; i < model.MaterialCount (); i++) { let material = model.GetMaterial (i); - if (material.isDefault) { + if (material.source === MaterialSource.DefaultFace) { material.color = color; } } diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index 1625eb2..7e93343 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -1,7 +1,7 @@ import { RunTasksBatch } from '../core/taskrunner.js'; import { IsEqual } from '../geometry/geometry.js'; import { CreateObjectUrl, CreateObjectUrlWithMimeType } from '../io/bufferutils.js'; -import { MaterialType } from '../model/material.js'; +import { MaterialSource, MaterialType } from '../model/material.js'; import { MeshInstance, MeshInstanceId } from '../model/meshinstance.js'; import { IsEmptyMesh } from '../model/meshutils.js'; import { ConvertColorToThreeColor, GetShadingType, ShadingType } from './threeutils.js'; @@ -204,7 +204,8 @@ export class ThreeMaterialHandler threeMaterial.emissiveMap = threeTexture; }); - if (material.isDefault) { + if (material.source !== MaterialSource.Model) { + threeMaterial.userData.source = material.source; this.conversionOutput.defaultMaterials.push (threeMaterial); } @@ -225,7 +226,8 @@ export class ThreeMaterialHandler } let threeMaterial = new THREE.LineBasicMaterial (materialParams); - if (material.isDefault) { + if (material.source !== MaterialSource.Model) { + threeMaterial.userData.source = material.source; this.conversionOutput.defaultMaterials.push (threeMaterial); } diff --git a/source/engine/threejs/threemodelloader.js b/source/engine/threejs/threemodelloader.js index 7be28f6..bb695cf 100644 --- a/source/engine/threejs/threemodelloader.js +++ b/source/engine/threejs/threemodelloader.js @@ -1,6 +1,7 @@ import { Direction } from '../geometry/geometry.js'; import { Importer } from '../import/importer.js'; import { RevokeObjectUrl } from '../io/bufferutils.js'; +import { MaterialSource } from '../model/material.js'; import { ConvertModelToThreeObject, ModelToThreeConversionOutput, ModelToThreeConversionParams } from './threeconverter.js'; import { ConvertColorToThreeColor, HasHighpDriverIssue } from './threeutils.js'; @@ -95,7 +96,7 @@ export class ThreeModelLoader { if (this.defaultMaterials !== null) { for (let defaultMaterial of this.defaultMaterials) { - if (!defaultMaterial.vertexColors) { + if (!defaultMaterial.vertexColors && defaultMaterial.userData.source === MaterialSource.DefaultFace) { defaultMaterial.color = ConvertColorToThreeColor (defaultColor); } } diff --git a/source/website/sidebardetailspanel.js b/source/website/sidebardetailspanel.js index cc998c8..4981c01 100644 --- a/source/website/sidebardetailspanel.js +++ b/source/website/sidebardetailspanel.js @@ -7,7 +7,7 @@ import { AddDiv, AddDomElement, ClearDomElement } from '../engine/viewer/domutil import { SidebarPanel } from './sidebarpanel.js'; import { CreateInlineColorCircle } from './utils.js'; import { GetFileName, IsUrl } from '../engine/io/fileutils.js'; -import { MaterialType } from '../engine/model/material.js'; +import { MaterialSource, MaterialType } from '../engine/model/material.js'; import { RGBColorToHexString } from '../engine/model/color.js'; import { Unit } from '../engine/model/unit.js'; @@ -104,7 +104,8 @@ export class SidebarDetailsPanel extends SidebarPanel } else if (material.type === MaterialType.Physical) { typeString = 'Physical'; } - this.AddProperty (table, new Property (PropertyType.Text, 'Source', material.isDefault ? 'Default' : 'Model')); + let materialSource = (material.source !== MaterialSource.Model) ? 'Default' : 'Model'; + this.AddProperty (table, new Property (PropertyType.Text, 'Source', materialSource)); this.AddProperty (table, new Property (PropertyType.Text, 'Type', typeString)); if (material.vertexColors) { this.AddProperty (table, new Property (PropertyType.Text, 'Color', 'Vertex colors')); From ac1a0e5b9d44850e5b6cfaba4c7735563aaaefff Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 13:12:51 +0200 Subject: [PATCH 19/29] Add default line color picker to settings. --- source/engine/import/importer.js | 4 ++ source/engine/import/importerbase.js | 1 + source/engine/main.js | 7 +-- source/engine/model/modelutils.js | 11 +++-- source/engine/threejs/threemodelloader.js | 10 +++-- source/engine/viewer/embeddedviewer.js | 1 + source/website/settings.js | 4 ++ source/website/sidebar.js | 4 +- source/website/sidebarsettingspanel.js | 53 ++++++++++++++++++----- source/website/website.js | 17 +++++--- test/tests/exporter_test.js | 24 ++++++++++ test/tests/importer_test.js | 1 - test/utils/testfiles.js | 3 ++ 13 files changed, 109 insertions(+), 31 deletions(-) diff --git a/source/engine/import/importer.js b/source/engine/import/importer.js index 2cd1758..4e4833e 100644 --- a/source/engine/import/importer.js +++ b/source/engine/import/importer.js @@ -21,6 +21,7 @@ export class ImportSettings { constructor () { + this.defaultLineColor = new RGBColor (100, 100, 100); this.defaultColor = new RGBColor (200, 200, 200); } } @@ -215,6 +216,9 @@ export class Importer }); importer.Import (mainFile.file.name, mainFile.file.extension, mainFile.file.content, { + getDefaultLineMaterialColor : () => { + return settings.defaultLineColor; + }, getDefaultMaterialColor : () => { return settings.defaultColor; }, diff --git a/source/engine/import/importerbase.js b/source/engine/import/importerbase.js index 58dc987..4e3a41b 100644 --- a/source/engine/import/importerbase.js +++ b/source/engine/import/importerbase.js @@ -58,6 +58,7 @@ export class ImporterBase } FinalizeModel (this.model, { + defaultLineMaterialColor : this.callbacks.getDefaultLineMaterialColor (), defaultMaterialColor : this.callbacks.getDefaultMaterialColor () }); diff --git a/source/engine/main.js b/source/engine/main.js index 4dc7308..066feaf 100644 --- a/source/engine/main.js +++ b/source/engine/main.js @@ -47,14 +47,14 @@ import { TextWriter } from './io/textwriter.js'; import { RGBColor, RGBAColor, ColorComponentFromFloat, ColorComponentToFloat, RGBColorFromFloatComponents, SRGBToLinear, LinearToSRGB, IntegerToHexString, RGBColorToHexString, RGBAColorToHexString, HexStringToRGBColor, HexStringToRGBAColor, ArrayToRGBColor, RGBColorIsEqual } from './model/color.js'; import { GeneratorParams, Generator, GeneratorHelper, GenerateCuboid, GenerateCone, GenerateCylinder, GenerateSphere, GeneratePlatonicSolid } from './model/generator.js'; import { Line } from './model/line.js'; -import { TextureMap, MaterialBase, FaceMaterial, PhongMaterial, PhysicalMaterial, TextureMapIsEqual, TextureIsEqual, MaterialType } from './model/material.js'; +import { TextureMap, MaterialBase, FaceMaterial, PhongMaterial, PhysicalMaterial, TextureMapIsEqual, TextureIsEqual, MaterialType, MaterialSource } from './model/material.js'; import { Mesh } from './model/mesh.js'; import { MeshPrimitiveBuffer, MeshBuffer, ConvertMeshToMeshBuffer } from './model/meshbuffer.js'; import { MeshInstanceId, MeshInstance } from './model/meshinstance.js'; import { IsEmptyMesh, CalculateTriangleNormal, TransformMesh, FlipMeshTrianglesOrientation } from './model/meshutils.js'; import { Model } from './model/model.js'; import { FinalizeModel, CheckModel } from './model/modelfinalization.js'; -import { IsModelEmpty, GetBoundingBox, GetTopology, IsTwoManifold, HasDefaultMaterial, ReplaceDefaultMaterialsColor } from './model/modelutils.js'; +import { IsModelEmpty, GetBoundingBox, GetTopology, IsTwoManifold, GetDefaultMaterials, ReplaceDefaultMaterialsColor } from './model/modelutils.js'; import { Node } from './model/node.js'; import { Object3D, ModelObject3D } from './model/object.js'; import { Property, PropertyGroup, PropertyToString, PropertyType } from './model/property.js'; @@ -236,6 +236,7 @@ export { TextureMapIsEqual, TextureIsEqual, MaterialType, + MaterialSource, Mesh, MeshPrimitiveBuffer, MeshBuffer, @@ -253,7 +254,7 @@ export { GetBoundingBox, GetTopology, IsTwoManifold, - HasDefaultMaterial, + GetDefaultMaterials, ReplaceDefaultMaterialsColor, Node, Object3D, diff --git a/source/engine/model/modelutils.js b/source/engine/model/modelutils.js index 70724b1..b4cad17 100644 --- a/source/engine/model/modelutils.js +++ b/source/engine/model/modelutils.js @@ -96,23 +96,26 @@ export function IsTwoManifold (object3D) } } -export function HasDefaultMaterial (model) +export function GetDefaultMaterials (model) { + let defaultMaterials = []; for (let i = 0; i < model.MaterialCount (); i++) { let material = model.GetMaterial (i); if (material.source !== MaterialSource.Model && !material.vertexColors) { - return true; + defaultMaterials.push (material); } } - return false; + return defaultMaterials; } -export function ReplaceDefaultMaterialsColor (model, color) +export function ReplaceDefaultMaterialsColor (model, color, lineColor) { for (let i = 0; i < model.MaterialCount (); i++) { let material = model.GetMaterial (i); if (material.source === MaterialSource.DefaultFace) { material.color = color; + } else if (material.source === MaterialSource.DefaultLine) { + material.color = lineColor; } } } diff --git a/source/engine/threejs/threemodelloader.js b/source/engine/threejs/threemodelloader.js index bb695cf..94d5bc4 100644 --- a/source/engine/threejs/threemodelloader.js +++ b/source/engine/threejs/threemodelloader.js @@ -92,12 +92,16 @@ export class ThreeModelLoader return this.defaultMaterials; } - ReplaceDefaultMaterialsColor (defaultColor) + ReplaceDefaultMaterialsColor (defaultColor, defaultLineColor) { if (this.defaultMaterials !== null) { for (let defaultMaterial of this.defaultMaterials) { - if (!defaultMaterial.vertexColors && defaultMaterial.userData.source === MaterialSource.DefaultFace) { - defaultMaterial.color = ConvertColorToThreeColor (defaultColor); + if (!defaultMaterial.vertexColors) { + if (defaultMaterial.userData.source === MaterialSource.DefaultFace) { + defaultMaterial.color = ConvertColorToThreeColor (defaultColor); + } else if (defaultMaterial.userData.source === MaterialSource.DefaultLine) { + defaultMaterial.color = ConvertColorToThreeColor (defaultLineColor); + } } } } diff --git a/source/engine/viewer/embeddedviewer.js b/source/engine/viewer/embeddedviewer.js index 6695405..24c3f59 100644 --- a/source/engine/viewer/embeddedviewer.js +++ b/source/engine/viewer/embeddedviewer.js @@ -109,6 +109,7 @@ export class EmbeddedViewer this.viewer.Clear (); let settings = new ImportSettings (); + console.log (this.parameters); if (this.parameters.defaultColor) { settings.defaultColor = this.parameters.defaultColor; } diff --git a/source/website/settings.js b/source/website/settings.js index 5b68552..d024213 100644 --- a/source/website/settings.js +++ b/source/website/settings.js @@ -18,9 +18,11 @@ export class Settings this.backgroundIsEnvMap = false; if (this.themeId === Theme.Light) { this.backgroundColor = new RGBAColor (255, 255, 255, 255); + this.defaultLineColor = new RGBColor (100, 100, 100); this.defaultColor = new RGBColor (200, 200, 200); } else if (this.themeId === Theme.Dark) { this.backgroundColor = new RGBAColor (42, 43, 46, 255); + this.defaultLineColor = new RGBColor (100, 100, 100); this.defaultColor = new RGBColor (200, 200, 200); } this.edgeSettings = new EdgeSettings (false, new RGBColor (0, 0, 0), 1); @@ -32,6 +34,7 @@ export class Settings this.environmentMapName = CookieGetStringVal ('ov_environment_map', 'fishermans_bastion'); this.backgroundIsEnvMap = CookieGetBoolVal ('ov_background_is_envmap', false); this.backgroundColor = CookieGetRGBAColorVal ('ov_background_color', new RGBAColor (255, 255, 255, 255)); + this.defaultLineColor = CookieGetRGBColorVal ('ov_default_line_color', new RGBColor (100, 100, 100)); this.defaultColor = CookieGetRGBColorVal ('ov_default_color', new RGBColor (200, 200, 200)); this.edgeSettings.showEdges = CookieGetBoolVal ('ov_show_edges', false); this.edgeSettings.edgeColor = CookieGetRGBColorVal ('ov_edge_color', new RGBColor (0, 0, 0)); @@ -44,6 +47,7 @@ export class Settings CookieSetStringVal ('ov_environment_map', this.environmentMapName); CookieSetBoolVal ('ov_background_is_envmap', this.backgroundIsEnvMap); CookieSetRGBAColorVal ('ov_background_color', this.backgroundColor); + CookieSetRGBColorVal ('ov_default_line_color', this.defaultLineColor); CookieSetRGBColorVal ('ov_default_color', this.defaultColor); CookieSetBoolVal ('ov_show_edges', this.edgeSettings.showEdges); CookieSetRGBColorVal ('ov_edge_color', this.edgeSettings.edgeColor); diff --git a/source/website/sidebar.js b/source/website/sidebar.js index be6d595..ea6f051 100644 --- a/source/website/sidebar.js +++ b/source/website/sidebar.js @@ -48,8 +48,8 @@ export class Sidebar getProjectionMode : () => { return this.callbacks.getProjectionMode (); }, - hasDefaultMaterial : () => { - return this.callbacks.hasDefaultMaterial (); + getDefaultMaterials : () => { + return this.callbacks.getDefaultMaterials (); }, onEnvironmentMapChanged : () => { this.callbacks.onEnvironmentMapChanged (); diff --git a/source/website/sidebarsettingspanel.js b/source/website/sidebarsettingspanel.js index 8c51ff7..5ed9008 100644 --- a/source/website/sidebarsettingspanel.js +++ b/source/website/sidebarsettingspanel.js @@ -10,6 +10,7 @@ import { ProjectionMode } from '../engine/viewer/camera.js'; import * as Pickr from '@simonwep/pickr'; import '@simonwep/pickr/dist/themes/monolith.min.css'; +import { MaterialSource } from '../engine/main.js'; function AddColorPicker (parentDiv, opacity, defaultColor, predefinedColors, onChange) { @@ -375,22 +376,35 @@ class SettingsImportParametersSection extends SettingsSection constructor (parentDiv, settings) { super (parentDiv, 'Import Settings', settings); + this.defaultColorPickerDiv = null; + this.defaultLineColorPickerDiv = null; this.defaultColorPicker = null; + this.defaultLineColorPicker = null; } Init (callbacks) { - super.Init (callbacks); + function AddDefaultColorPicker (contentDiv, name, defaultColor, onChange) + { + let colorDiv = AddDiv (contentDiv, 'ov_sidebar_parameter'); + let colorInput = AddDiv (colorDiv, 'ov_color_picker'); + AddDiv (colorDiv, null, name); + let predefinedDefaultColors = ['#ffffff', '#e3e3e3', '#cc3333', '#fac832', '#4caf50', '#3393bd', '#9b27b0', '#fda4b8']; + let defaultColorStr = '#' + RGBColorToHexString (defaultColor); + return AddColorPicker (colorInput, false, defaultColorStr, predefinedDefaultColors, onChange); + } - let defaultColorDiv = AddDiv (this.contentDiv, 'ov_sidebar_parameter'); - let defaultColorInput = AddDiv (defaultColorDiv, 'ov_color_picker'); - AddDiv (defaultColorDiv, null, 'Default Color'); - let predefinedDefaultColors = ['#ffffff', '#e3e3e3', '#cc3333', '#fac832', '#4caf50', '#3393bd', '#9b27b0', '#fda4b8']; - let defaultColor = '#' + RGBColorToHexString (this.settings.defaultColor); - this.defaultColorPicker = AddColorPicker (defaultColorInput, false, defaultColor, predefinedDefaultColors, (r, g, b, a) => { + super.Init (callbacks); + this.defaultColorPickerDiv = AddDiv (this.contentDiv); + this.defaultColorPicker = AddDefaultColorPicker (this.defaultColorPickerDiv, 'Default Color', this.settings.defaultColor, (r, g, b, a) => { this.settings.defaultColor = new RGBColor (r, g, b); this.callbacks.onDefaultColorChanged (); }); + this.defaultLineColorPickerDiv = AddDiv (this.contentDiv); + this.defaultLineColorPicker = AddDefaultColorPicker (this.defaultLineColorPickerDiv, 'Default Line Color', this.settings.defaultLineColor, (r, g, b, a) => { + this.settings.defaultLineColor = new RGBColor (r, g, b); + this.callbacks.onDefaultColorChanged (); + }); } Update () @@ -398,13 +412,26 @@ class SettingsImportParametersSection extends SettingsSection if (this.defaultColorPicker !== null) { this.defaultColorPicker.setColor ('#' + RGBColorToHexString (this.settings.defaultColor)); } + if (this.defaultLineColorPicker !== null) { + this.defaultLineColorPicker.setColor ('#' + RGBColorToHexString (this.settings.defaultLineColor)); + } } UpdateVisibility () { if (this.contentDiv !== null) { - let hasDefaultMaterial = this.callbacks.hasDefaultMaterial (); - ShowDomElement (this.contentDiv, hasDefaultMaterial); + let defaultMaterials = this.callbacks.getDefaultMaterials (); + if (defaultMaterials.length === 0) { + ShowDomElement (this.contentDiv, false); + } else { + let sources = new Set (); + for (let material of defaultMaterials) { + sources.add (material.source); + } + ShowDomElement (this.contentDiv, true); + ShowDomElement (this.defaultColorPickerDiv, sources.has (MaterialSource.DefaultFace)); + ShowDomElement (this.defaultLineColorPickerDiv, sources.has (MaterialSource.DefaultLine)); + } } } @@ -413,6 +440,9 @@ class SettingsImportParametersSection extends SettingsSection if (this.defaultColorPicker !== null) { this.defaultColorPicker.hide (); } + if (this.defaultLineColorPicker !== null) { + this.defaultLineColorPicker.hide (); + } } } @@ -482,8 +512,8 @@ export class SidebarSettingsPanel extends SidebarPanel } }); this.importParametersSection.Init ({ - hasDefaultMaterial : () => { - return this.callbacks.hasDefaultMaterial (); + getDefaultMaterials : () => { + return this.callbacks.getDefaultMaterials (); }, onDefaultColorChanged : () => { this.callbacks.onDefaultColorChanged (); @@ -511,6 +541,7 @@ export class SidebarSettingsPanel extends SidebarPanel this.settings.environmentMapName = defaultSettings.environmentMapName; this.settings.backgroundIsEnvMap = defaultSettings.backgroundIsEnvMap; this.settings.backgroundColor = defaultSettings.backgroundColor; + this.settings.defaultLineColor = defaultSettings.defaultLineColor; this.settings.defaultColor = defaultSettings.defaultColor; this.settings.edgeSettings = defaultSettings.edgeSettings; this.settings.themeId = defaultSettings.themeId; diff --git a/source/website/website.js b/source/website/website.js index 38016bc..8e4729f 100644 --- a/source/website/website.js +++ b/source/website/website.js @@ -19,7 +19,7 @@ import { ShowSnapshotDialog } from './snapshotdialog.js'; import { AddSvgIconElement, GetFilesFromDataTransfer, InstallTooltip, IsSmallWidth } from './utils.js'; import { ShowOpenUrlDialog } from './openurldialog.js'; import { ShowSharingDialog } from './sharingdialog.js'; -import { HasDefaultMaterial, ReplaceDefaultMaterialsColor } from '../engine/model/modelutils.js'; +import { GetDefaultMaterials, ReplaceDefaultMaterialsColor } from '../engine/model/modelutils.js'; import { Direction } from '../engine/geometry/geometry.js'; import { CookieGetBoolVal, CookieSetBoolVal } from './cookiehandler.js'; import { MeasureTool } from './measuretool.js'; @@ -402,6 +402,7 @@ export class Website } TransformFileHostUrls (urls); let importSettings = new ImportSettings (); + importSettings.defaultLineColor = this.settings.defaultLineColor; importSettings.defaultColor = this.settings.defaultColor; let defaultColor = this.hashHandler.GetDefaultColorFromHash (); if (defaultColor !== null) { @@ -480,6 +481,7 @@ export class Website LoadModelFromFileList (files) { let importSettings = new ImportSettings (); + importSettings.defaultLineColor = this.settings.defaultLineColor; importSettings.defaultColor = this.settings.defaultColor; let inputFiles = InputFilesFromFileObjects (files); this.LoadModelFromInputFiles (inputFiles, importSettings); @@ -572,14 +574,15 @@ export class Website if (resetColors) { let defaultSettings = new Settings (this.settings.themeId); this.settings.backgroundColor = defaultSettings.backgroundColor; + this.settings.defaultLineColor = defaultSettings.defaultLineColor; this.settings.defaultColor = defaultSettings.defaultColor; this.sidebar.UpdateControlsStatus (); this.viewer.SetBackgroundColor (this.settings.backgroundColor); let modelLoader = this.modelLoaderUI.GetModelLoader (); if (modelLoader.GetDefaultMaterials () !== null) { - ReplaceDefaultMaterialsColor (this.model, this.settings.defaultColor); - modelLoader.ReplaceDefaultMaterialsColor (this.settings.defaultColor); + ReplaceDefaultMaterialsColor (this.model, this.settings.defaultColor, this.settings.defaultLineColor); + modelLoader.ReplaceDefaultMaterialsColor (this.settings.defaultColor, this.settings.defaultLineColor); } } @@ -794,8 +797,8 @@ export class Website getProjectionMode : () => { return this.viewer.GetProjectionMode (); }, - hasDefaultMaterial : () => { - return HasDefaultMaterial (this.model); + getDefaultMaterials : () => { + return GetDefaultMaterials (this.model); }, onEnvironmentMapChanged : () => { this.settings.SaveToCookies (); @@ -815,8 +818,8 @@ export class Website this.settings.SaveToCookies (); let modelLoader = this.modelLoaderUI.GetModelLoader (); if (modelLoader.GetDefaultMaterials () !== null) { - ReplaceDefaultMaterialsColor (this.model, this.settings.defaultColor); - modelLoader.ReplaceDefaultMaterialsColor (this.settings.defaultColor); + ReplaceDefaultMaterialsColor (this.model, this.settings.defaultColor, this.settings.defaultLineColor); + modelLoader.ReplaceDefaultMaterialsColor (this.settings.defaultColor, this.settings.defaultLineColor); } this.viewer.Render (); }, diff --git a/test/tests/exporter_test.js b/test/tests/exporter_test.js index 1302678..5425add 100644 --- a/test/tests/exporter_test.js +++ b/test/tests/exporter_test.js @@ -219,6 +219,9 @@ describe ('Exporter', function () { let contentBuffer = stlFile.GetBufferContent (); let importer = new OV.ImporterStl (); importer.Import (stlFile.GetName (), 'stl', contentBuffer, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, @@ -316,6 +319,9 @@ describe ('Exporter', function () { let contentBuffer = plyFile.GetBufferContent (); let importer = new OV.ImporterPly (); importer.Import (plyFile.GetName (), 'ply', contentBuffer, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, @@ -347,6 +353,9 @@ describe ('Exporter', function () { let contentBuffer = gltfFile.GetBufferContent (); let importer = new OV.ImporterGltf (); importer.Import (gltfFile.GetName (), 'gltf', contentBuffer, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, @@ -383,6 +392,9 @@ describe ('Exporter', function () { let contentBuffer = glbFile.GetBufferContent (); let importer = new OV.ImporterGltf (); importer.Import (glbFile.GetName (), 'glb', contentBuffer, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, @@ -416,6 +428,9 @@ describe ('Exporter', function () { let contentBuffer = glbFile.GetBufferContent (); let importer = new OV.ImporterGltf (); importer.Import (glbFile.GetName (), 'glb', contentBuffer, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, @@ -451,6 +466,9 @@ describe ('Exporter', function () { let contentBuffer = glbFile.GetBufferContent (); let importer = new OV.ImporterGltf (); importer.Import (glbFile.GetName (), 'glb', contentBuffer, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, @@ -486,6 +504,9 @@ describe ('Exporter', function () { let contentBuffer = glbFile.GetBufferContent (); let importer = new OV.ImporterGltf (); importer.Import (glbFile.GetName (), 'glb', contentBuffer, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, @@ -521,6 +542,9 @@ describe ('Exporter', function () { let contentBuffer = glbFile.GetBufferContent (); let importer = new OV.ImporterGltf (); importer.Import (glbFile.GetName (), 'glb', contentBuffer, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, diff --git a/test/tests/importer_test.js b/test/tests/importer_test.js index 23e7525..eb09dfe 100644 --- a/test/tests/importer_test.js +++ b/test/tests/importer_test.js @@ -277,7 +277,6 @@ describe ('Importer Test', function () { onFileLoadProgress : (current, total) => { }, onImportStart : function () { - }, onImportSuccess : function (importResult) { assert.ok (!OV.IsModelEmpty (importResult.model)); diff --git a/test/utils/testfiles.js b/test/utils/testfiles.js index b9a6a8b..99b4dc9 100644 --- a/test/utils/testfiles.js +++ b/test/utils/testfiles.js @@ -11,6 +11,9 @@ export function ImportFile (importer, folder, fileName, onReady) return fileContent; }); importer.Import (fileName, extension, content, { + getDefaultLineMaterialColor () { + return new OV.RGBColor (0, 0, 0); + }, getDefaultMaterialColor () { return new OV.RGBColor (0, 0, 0); }, From 9e5ddaead77fe01f665c36648a269171255770ee Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 13:52:06 +0200 Subject: [PATCH 20/29] Allow default line color parameter when embedding. --- docs/Class_EmbeddedViewer.html | 8 +++ sandbox/embed_lines.html | 61 +++++++++++++++++++++++ source/engine/parameters/parameterlist.js | 12 +++++ source/engine/viewer/embeddedviewer.js | 13 ++++- source/website/embed.js | 4 ++ source/website/hashhandler.js | 6 +++ source/website/sharingdialog.js | 1 + test/testfiles/obj/cube_with_edges.mtl | 5 -- test/testfiles/obj/cube_with_edges.obj | 6 +-- test/tests/parameterlist_test.js | 5 ++ 10 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 sandbox/embed_lines.html diff --git a/docs/Class_EmbeddedViewer.html b/docs/Class_EmbeddedViewer.html index 50fdd21..078dfaa 100644 --- a/docs/Class_EmbeddedViewer.html +++ b/docs/Class_EmbeddedViewer.html @@ -112,6 +112,14 @@
Default color of the model. It has effect only if the imported model doesn't specify any color.
+defaultLineColor +RGBColor +(optional) +
+
+
Default line color of the model. It has effect only if the imported model doesn't specify any color.
+
+
edgeSettings EdgeSettings (optional) diff --git a/sandbox/embed_lines.html b/sandbox/embed_lines.html new file mode 100644 index 0000000..4e19e54 --- /dev/null +++ b/sandbox/embed_lines.html @@ -0,0 +1,61 @@ + + + + + + + + Online 3D Viewer + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+ + + diff --git a/source/engine/parameters/parameterlist.js b/source/engine/parameters/parameterlist.js index 55f8482..d1d171f 100644 --- a/source/engine/parameters/parameterlist.js +++ b/source/engine/parameters/parameterlist.js @@ -269,6 +269,12 @@ export class ParameterListBuilder return this; } + AddDefaultLineColor (color) + { + this.AddUrlPart ('defaultlinecolor', ParameterConverter.RGBColorToString (color)); + return this; + } + AddEdgeSettings (edgeSettings) { this.AddUrlPart ('edgesettings', ParameterConverter.EdgeSettingsToString (edgeSettings)); @@ -344,6 +350,12 @@ export class ParameterListParser return ParameterConverter.StringToRGBColor (colorParams); } + GetDefaultLineColor () + { + let colorParams = this.GetKeywordParams ('defaultlinecolor'); + return ParameterConverter.StringToRGBColor (colorParams); + } + GetEdgeSettings () { let edgeSettingsParams = this.GetKeywordParams ('edgesettings'); diff --git a/source/engine/viewer/embeddedviewer.js b/source/engine/viewer/embeddedviewer.js index 24c3f59..5f96af5 100644 --- a/source/engine/viewer/embeddedviewer.js +++ b/source/engine/viewer/embeddedviewer.js @@ -24,6 +24,8 @@ export class EmbeddedViewer * @param {RGBAColor} [parameters.backgroundColor] Background color of the canvas. * @param {RGBColor} [parameters.defaultColor] Default color of the model. It has effect only * if the imported model doesn't specify any color. + * @param {RGBColor} [parameters.defaultLineColor] Default line color of the model. It has effect only + * if the imported model doesn't specify any color. * @param {EdgeSettings} [parameters.edgeSettings] Edge settings. * @param {EnvironmentSettings} [parameters.environmentSettings] Environment settings. * @param {function} [parameters.onModelLoaded] Callback that is called when the model with all @@ -109,10 +111,12 @@ export class EmbeddedViewer this.viewer.Clear (); let settings = new ImportSettings (); - console.log (this.parameters); if (this.parameters.defaultColor) { settings.defaultColor = this.parameters.defaultColor; } + if (this.parameters.defaultLineColor) { + settings.defaultLineColor = this.parameters.defaultLineColor; + } this.model = null; let progressDiv = null; @@ -276,6 +280,12 @@ export function Init3DViewerElements (onReady) defaultColor = ParameterConverter.StringToRGBColor (defaultColorParams); } + let defaultLineColor = null; + let defaultLineColorParams = element.getAttribute ('defaultlinecolor'); + if (defaultLineColorParams) { + defaultLineColor = ParameterConverter.StringToRGBColor (defaultLineColorParams); + } + let edgeSettings = null; let edgeSettingsParams = element.getAttribute ('edgesettings'); if (edgeSettingsParams) { @@ -306,6 +316,7 @@ export function Init3DViewerElements (onReady) camera : camera, projectionMode : projectionMode, backgroundColor : backgroundColor, + defaultLineColor : defaultLineColor, defaultColor : defaultColor, edgeSettings : edgeSettings, environmentSettings : environmentSettings diff --git a/source/website/embed.js b/source/website/embed.js index d8e4e02..9e70b0f 100644 --- a/source/website/embed.js +++ b/source/website/embed.js @@ -68,6 +68,10 @@ export class Embed if (defaultColor !== null) { settings.defaultColor = defaultColor; } + let defaultLineColor = this.hashHandler.GetDefaultLineColorFromHash (); + if (defaultLineColor !== null) { + settings.defaultLineColor = defaultLineColor; + } let inputFiles = InputFilesFromUrls (urls); this.modelLoaderUI.LoadModel (inputFiles, settings, { onStart : () => diff --git a/source/website/hashhandler.js b/source/website/hashhandler.js index 8a13d29..b57b257 100644 --- a/source/website/hashhandler.js +++ b/source/website/hashhandler.js @@ -72,6 +72,12 @@ export class HashHandler return parser.GetDefaultColor (); } + GetDefaultLineColorFromHash () + { + let parser = CreateUrlParser (this.GetHash ()); + return parser.GetDefaultLineColor (); + } + GetEdgeSettingsFromHash () { let parser = CreateUrlParser (this.GetHash ()); diff --git a/source/website/sharingdialog.js b/source/website/sharingdialog.js index 8a7e2d0..db96a7f 100644 --- a/source/website/sharingdialog.js +++ b/source/website/sharingdialog.js @@ -71,6 +71,7 @@ export function ShowSharingDialog (fileList, settings, viewer) builder.AddEnvironmentSettings (environmentSettings); builder.AddBackgroundColor (settings.backgroundColor); builder.AddDefaultColor (settings.defaultColor); + builder.AddDefaultLineColor (settings.defaultLineColor); builder.AddEdgeSettings (settings.edgeSettings); } let hashParameters = builder.GetParameterList (); diff --git a/test/testfiles/obj/cube_with_edges.mtl b/test/testfiles/obj/cube_with_edges.mtl index edd0bee..3b2a291 100644 --- a/test/testfiles/obj/cube_with_edges.mtl +++ b/test/testfiles/obj/cube_with_edges.mtl @@ -3,11 +3,6 @@ Ka 0.000000 0.000000 0.000000 Kd 0.800000 0.000000 0.000000 Ks 0.500000 0.500000 0.500000 -newmtl Green -Ka 0.000000 0.000000 0.000000 -Kd 0.000000 0.800000 0.000000 -Ks 0.500000 0.500000 0.500000 - newmtl Blue Ka 0.000000 0.000000 0.000000 Kd 0.000000 0.000000 0.800000 diff --git a/test/testfiles/obj/cube_with_edges.obj b/test/testfiles/obj/cube_with_edges.obj index bdfdb79..b930c5f 100644 --- a/test/testfiles/obj/cube_with_edges.obj +++ b/test/testfiles/obj/cube_with_edges.obj @@ -29,16 +29,12 @@ f 1/1/6 4/2/6 3/3/6 2/4/6 f 2/1/1 3/2/1 7/3/1 6/4/1 f 4/1/2 1/2/2 5/3/2 8/4/2 f 5/1/5 6/2/5 7/3/5 8/4/5 - l 1 4 2 3 6 7 5 8 usemtl Red f 3/1/3 4/2/3 8/3/3 7/4/3 +l 1 2 2 6 6 5 5 1 usemtl Blue f 1/1/4 2/2/4 6/3/4 5/4/4 - -usemtl Green l 3 4 4 8 8 7 7 3 -l 1 2 2 6 6 5 5 1 - diff --git a/test/tests/parameterlist_test.js b/test/tests/parameterlist_test.js index 0cae66f..943f54c 100644 --- a/test/tests/parameterlist_test.js +++ b/test/tests/parameterlist_test.js @@ -16,6 +16,7 @@ describe ('Parameter List', function () { ); let background = new OV.RGBAColor (4, 5, 6, 7); let color = new OV.RGBColor (1, 2, 3); + let color2 = new OV.RGBColor (4, 5, 6); { let urlParams = OV.CreateUrlBuilder ().AddModelUrls (modelUrls).GetParameterList (); assert.strictEqual (urlParams, 'model=a.txt,b.txt'); @@ -36,6 +37,10 @@ describe ('Parameter List', function () { let urlParams = OV.CreateUrlBuilder ().AddModelUrls (modelUrls).AddCamera (camera).AddBackgroundColor (background).AddDefaultColor (color).GetParameterList (); assert.strictEqual (urlParams, 'model=a.txt,b.txt$camera=1.00000,1.00000,1.00000,0.00000,0.00000,0.00000,0.00000,0.00000,1.00000,45.00000$backgroundcolor=4,5,6,7$defaultcolor=1,2,3'); } + { + let urlParams = OV.CreateUrlBuilder ().AddModelUrls (modelUrls).AddCamera (camera).AddBackgroundColor (background).AddDefaultColor (color).AddDefaultLineColor (color2).GetParameterList (); + assert.strictEqual (urlParams, 'model=a.txt,b.txt$camera=1.00000,1.00000,1.00000,0.00000,0.00000,0.00000,0.00000,0.00000,1.00000,45.00000$backgroundcolor=4,5,6,7$defaultcolor=1,2,3$defaultlinecolor=4,5,6'); + } { let urlParams = OV.CreateUrlBuilder ().AddEdgeSettings (new EdgeSettings ( true, From bd34c2a408e92d4f217b492a3c373ee0769aa971 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 15:54:59 +0200 Subject: [PATCH 21/29] Show line count in the details panel. --- source/engine/model/line.js | 8 ++++++++ source/engine/model/mesh.js | 9 +++++++++ source/engine/model/meshinstance.js | 5 +++++ source/engine/model/model.js | 9 +++++++++ source/engine/model/object.js | 10 ++++++++++ source/website/sidebardetailspanel.js | 9 ++++++++- 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/source/engine/model/line.js b/source/engine/model/line.js index e88a962..f8860b3 100644 --- a/source/engine/model/line.js +++ b/source/engine/model/line.js @@ -22,6 +22,14 @@ export class Line return this; } + SegmentCount () + { + if (this.vertices === null) { + return 0; + } + return parseInt (this.vertices.length / 2, 10); + } + Clone () { let cloned = new Line ([...this.vertices]); diff --git a/source/engine/model/mesh.js b/source/engine/model/mesh.js index 753d9d4..9339c3b 100644 --- a/source/engine/model/mesh.js +++ b/source/engine/model/mesh.js @@ -38,6 +38,15 @@ export class Mesh extends ModelObject3D return this.lines.length; } + LineSegmentCount () + { + let lineSegmentCount = 0; + for (let line of this.lines) { + lineSegmentCount += line.SegmentCount (); + } + return lineSegmentCount; + } + TriangleCount () { return this.triangles.length; diff --git a/source/engine/model/meshinstance.js b/source/engine/model/meshinstance.js index 8b5b49a..b3b11a6 100644 --- a/source/engine/model/meshinstance.js +++ b/source/engine/model/meshinstance.js @@ -70,6 +70,11 @@ export class MeshInstance extends ModelObject3D return this.mesh.LineCount (); } + LineSegmentCount () + { + return this.mesh.LineSegmentCount (); + } + TriangleCount () { return this.mesh.TriangleCount (); diff --git a/source/engine/model/model.js b/source/engine/model/model.js index f8e32cb..dbafa3c 100644 --- a/source/engine/model/model.js +++ b/source/engine/model/model.js @@ -102,6 +102,15 @@ export class Model extends ModelObject3D return count; } + LineSegmentCount () + { + let count = 0; + this.EnumerateMeshInstances ((meshInstance) => { + count += meshInstance.LineSegmentCount (); + }); + return count; + } + TriangleCount () { let count = 0; diff --git a/source/engine/model/object.js b/source/engine/model/object.js index 10c4daa..eb9dd1a 100644 --- a/source/engine/model/object.js +++ b/source/engine/model/object.js @@ -25,6 +25,16 @@ export class Object3D return 0; } + LineCount () + { + return 0; + } + + LineSegmentCount () + { + return 0; + } + TriangleCount () { return 0; diff --git a/source/website/sidebardetailspanel.js b/source/website/sidebardetailspanel.js index 4981c01..73211bc 100644 --- a/source/website/sidebardetailspanel.js +++ b/source/website/sidebardetailspanel.js @@ -53,7 +53,14 @@ export class SidebarDetailsPanel extends SidebarPanel let size = SubCoord3D (boundingBox.max, boundingBox.min); let unit = model.GetUnit (); this.AddProperty (table, new Property (PropertyType.Integer, 'Vertices', object3D.VertexCount ())); - this.AddProperty (table, new Property (PropertyType.Integer, 'Triangles', object3D.TriangleCount ())); + let lineSegmentCount = object3D.LineSegmentCount (); + if (lineSegmentCount > 0) { + this.AddProperty (table, new Property (PropertyType.Integer, 'Lines', lineSegmentCount)); + } + let triangleCount = object3D.TriangleCount (); + if (triangleCount > 0) { + this.AddProperty (table, new Property (PropertyType.Integer, 'Triangles', triangleCount)); + } if (unit !== Unit.Unknown) { this.AddProperty (table, new Property (PropertyType.Text, 'Unit', UnitToString (unit))); } From 82c5d01a438129c1bc1efdeabe82373f38f2e38e Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 18:17:07 +0200 Subject: [PATCH 22/29] Fix measure tool with lines. --- source/website/measuretool.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/website/measuretool.js b/source/website/measuretool.js index b65e5cc..f86ed78 100644 --- a/source/website/measuretool.js +++ b/source/website/measuretool.js @@ -136,7 +136,7 @@ export class MeasureTool Click (mouseCoordinates) { let intersection = this.viewer.GetMeshIntersectionUnderMouse (mouseCoordinates); - if (intersection === null) { + if (intersection === null || !intersection.object.isMesh) { this.ClearMarkers (); this.UpdatePanel (); return; @@ -153,7 +153,7 @@ export class MeasureTool MouseMove (mouseCoordinates) { let intersection = this.viewer.GetMeshIntersectionUnderMouse (mouseCoordinates); - if (intersection === null) { + if (intersection === null || !intersection.object.isMesh) { if (this.tempMarker !== null) { this.tempMarker.Show (false); this.viewer.Render (); From 8a3c98e658c8f3355221622776385e46c139078d Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 20:27:21 +0200 Subject: [PATCH 23/29] The obj file format specifies continuous lines and not line segments. --- source/engine/import/importerobj.js | 2 +- source/engine/model/line.js | 2 +- source/engine/threejs/threeconverter.js | 8 ++++++-- test/testfiles/obj/cube_with_edges.obj | 9 ++++++--- test/testfiles/obj/lines.obj | 2 +- test/testfiles/obj/lines_colors.obj | 2 +- test/testfiles/obj/lines_in_meshes.obj | 2 +- test/testfiles/obj/lines_in_meshes_2.obj | 2 +- test/tests/importerobj_test.js | 8 ++++---- 9 files changed, 22 insertions(+), 15 deletions(-) diff --git a/source/engine/import/importerobj.js b/source/engine/import/importerobj.js index b26dae9..839a6b4 100644 --- a/source/engine/import/importerobj.js +++ b/source/engine/import/importerobj.js @@ -220,7 +220,7 @@ export class ImporterObj extends ImporterBase )); return true; } else if (keyword === 'l') { - if (parameters.length < 2 || parameters.length % 2 !== 0) { + if (parameters.length < 2) { return true; } this.ProcessLineCommand (parameters); diff --git a/source/engine/model/line.js b/source/engine/model/line.js index f8860b3..28fec18 100644 --- a/source/engine/model/line.js +++ b/source/engine/model/line.js @@ -27,7 +27,7 @@ export class Line if (this.vertices === null) { return 0; } - return parseInt (this.vertices.length / 2, 10); + return this.vertices.length - 1; } Clone () diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index 7e93343..0c6f84f 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -445,12 +445,16 @@ export function ConvertModelToThreeObject (model, conversionParams, conversionOu for (let i = 0; i < lineIndices.length; i++) { let line = mesh.GetLine (lineIndices[i]); let lineVertices = line.GetVertices (); - for (let vertexIndex of lineVertices) { + for (let i = 0; i < lineVertices.length; i++) { + let vertexIndex = lineVertices[i]; let vertex = mesh.GetVertex (vertexIndex); vertices.push (vertex.x, vertex.y, vertex.z); + if (i > 0 && i < lineVertices.length - 1) { + vertices.push (vertex.x, vertex.y, vertex.z); + } } meshMaterialHandler.ProcessItem (segmentCount, line.mat); - segmentCount += lineVertices.length / 2; + segmentCount += line.SegmentCount (); } meshMaterialHandler.Finalize (segmentCount); diff --git a/test/testfiles/obj/cube_with_edges.obj b/test/testfiles/obj/cube_with_edges.obj index b930c5f..4057ee8 100644 --- a/test/testfiles/obj/cube_with_edges.obj +++ b/test/testfiles/obj/cube_with_edges.obj @@ -29,12 +29,15 @@ f 1/1/6 4/2/6 3/3/6 2/4/6 f 2/1/1 3/2/1 7/3/1 6/4/1 f 4/1/2 1/2/2 5/3/2 8/4/2 f 5/1/5 6/2/5 7/3/5 8/4/5 -l 1 4 2 3 6 7 5 8 +l 1 4 +l 2 3 +l 6 7 +l 5 8 usemtl Red f 3/1/3 4/2/3 8/3/3 7/4/3 -l 1 2 2 6 6 5 5 1 +l 1 2 6 5 1 usemtl Blue f 1/1/4 2/2/4 6/3/4 5/4/4 -l 3 4 4 8 8 7 7 3 +l 3 4 8 7 3 diff --git a/test/testfiles/obj/lines.obj b/test/testfiles/obj/lines.obj index 58f2e8b..2bc3c89 100644 --- a/test/testfiles/obj/lines.obj +++ b/test/testfiles/obj/lines.obj @@ -8,4 +8,4 @@ v 1.0 1.0 1.0 v 0.0 1.0 1.0 l 1 2 l 3 4 -l 5 6 6 7 7 8 8 5 +l 5 6 7 8 5 diff --git a/test/testfiles/obj/lines_colors.obj b/test/testfiles/obj/lines_colors.obj index 9e55285..3c6e84b 100644 --- a/test/testfiles/obj/lines_colors.obj +++ b/test/testfiles/obj/lines_colors.obj @@ -12,7 +12,7 @@ usemtl Red l 1 2 l 3 4 usemtl Green -l 5 6 6 7 7 8 8 5 +l 5 6 7 8 5 usemtl Blue l 1 5 diff --git a/test/testfiles/obj/lines_in_meshes.obj b/test/testfiles/obj/lines_in_meshes.obj index 2f52e8a..59f4b24 100644 --- a/test/testfiles/obj/lines_in_meshes.obj +++ b/test/testfiles/obj/lines_in_meshes.obj @@ -10,4 +10,4 @@ g Mesh01 l 1 2 l 3 4 g Mesh02 -l 5 6 6 7 7 8 8 5 +l 5 6 7 8 5 diff --git a/test/testfiles/obj/lines_in_meshes_2.obj b/test/testfiles/obj/lines_in_meshes_2.obj index 0f3cb25..725e472 100644 --- a/test/testfiles/obj/lines_in_meshes_2.obj +++ b/test/testfiles/obj/lines_in_meshes_2.obj @@ -13,4 +13,4 @@ v 1.0 1.0 1.0 v 0.0 1.0 1.0 g Mesh02 -l 5 6 6 7 7 8 8 5 +l 5 6 7 8 5 diff --git a/test/tests/importerobj_test.js b/test/tests/importerobj_test.js index bd372b5..24ddaa8 100644 --- a/test/tests/importerobj_test.js +++ b/test/tests/importerobj_test.js @@ -668,7 +668,7 @@ describe ('Obj Importer', function () { mat : 0 }, { - vertices : [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1], + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1], mat : 0 } ], @@ -707,7 +707,7 @@ describe ('Obj Importer', function () { name : 'Mesh02', lines : [ { - vertices : [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1], + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1], mat : 0 } ], @@ -746,7 +746,7 @@ describe ('Obj Importer', function () { name : 'Mesh02', lines : [ { - vertices : [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1], + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1], mat : 0 } ], @@ -781,7 +781,7 @@ describe ('Obj Importer', function () { mat : 0 }, { - vertices : [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1], + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1], mat : 1 }, { From 96e008133557b24dab693c9ee027d32268c30dfa Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 20:28:48 +0200 Subject: [PATCH 24/29] Minor modification. --- test/tests/exportimport_test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/tests/exportimport_test.js b/test/tests/exportimport_test.js index 9678390..f9bbb08 100644 --- a/test/tests/exportimport_test.js +++ b/test/tests/exportimport_test.js @@ -119,14 +119,12 @@ function ExportImport (model, format, extension, onReady) let fileObjects = exportedFiles.map (file => new OV.InputFile (file.name, OV.FileSource.File, new FileObject ('', file.name, file.content))); importer.ImportFiles (fileObjects, settings, { onLoadStart : function () { - }, onFileListProgress : (current, total) => { }, onFileLoadProgress : (current, total) => { }, onImportStart : function () { - }, onImportSuccess : function (importResult) { onReady (importResult.model) @@ -152,6 +150,7 @@ function CheckSingleMeshModel (model, model2) assert.strictEqual (model2.MaterialCount (), 1); assert.strictEqual (model2.MeshInstanceCount (), 1); assert.strictEqual (model.TriangleCount (), model2.TriangleCount ()); + assert.strictEqual (model.LineSegmentCount (), model2.LineSegmentCount ()); CheckModelBounds (model, model2); } @@ -160,6 +159,7 @@ function CheckModel (model, model2) assert.strictEqual (model.MaterialCount (), model2.MaterialCount ()); assert.strictEqual (model.MeshInstanceCount (), model2.MeshInstanceCount ()); assert.strictEqual (model.TriangleCount (), model2.TriangleCount ()); + assert.strictEqual (model.LineSegmentCount (), model2.LineSegmentCount ()); CheckModelBounds (model, model2); } From 040ef5aa7789ffc8cf5c9df817b310837229e83f Mon Sep 17 00:00:00 2001 From: kovacsv Date: Mon, 23 Oct 2023 20:34:29 +0200 Subject: [PATCH 25/29] Add line count to tests. --- test/tests/importer3ds_test.js | 16 +++++++++++ test/tests/importergltf_test.js | 49 ++++++++++++++++++++++++--------- test/tests/importerobj_test.js | 5 ++++ test/tests/importeroff_test.js | 1 + test/tests/importerply_test.js | 4 +++ test/tests/importerstl_test.js | 4 +++ test/utils/testutils.js | 1 + 7 files changed, 67 insertions(+), 13 deletions(-) diff --git a/test/tests/importer3ds_test.js b/test/tests/importer3ds_test.js index 2c67dde..610a441 100644 --- a/test/tests/importer3ds_test.js +++ b/test/tests/importer3ds_test.js @@ -26,6 +26,7 @@ describe ('3ds Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 8, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -57,6 +58,7 @@ describe ('3ds Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 8, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -88,6 +90,7 @@ describe ('3ds Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 8, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -100,6 +103,7 @@ describe ('3ds Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 8, + lineCount : 0, triangleCount : 12, boundingBox : { min : [2, 0, 0], @@ -131,6 +135,7 @@ describe ('3ds Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 8, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -143,6 +148,7 @@ describe ('3ds Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 8, + lineCount : 0, triangleCount : 12, boundingBox : { min : [2, 0, 0], @@ -155,6 +161,7 @@ describe ('3ds Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 8, + lineCount : 0, triangleCount : 12, boundingBox : { min : [2, 2, 0], @@ -167,6 +174,7 @@ describe ('3ds Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 8, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 2, 0], @@ -192,6 +200,7 @@ describe ('3ds Importer', function() { vertexColorCount: 0, normalCount: 12, uvCount: 8, + lineCount : 0, triangleCount: 12, boundingBox: { min: [ -1, -1, -1 ], max: [ 1, 1, 1 ] } }, @@ -201,6 +210,7 @@ describe ('3ds Importer', function() { vertexColorCount: 0, normalCount: 12, uvCount: 8, + lineCount : 0, triangleCount: 12, boundingBox: { min: [ 2, -1, -1 ], max: [ 4, 1, 1 ] } }, @@ -210,6 +220,7 @@ describe ('3ds Importer', function() { vertexColorCount: 0, normalCount: 12, uvCount: 8, + lineCount : 0, triangleCount: 12, boundingBox: { min: [ 2, 2, -1 ], max: [ 4, 4, 1 ] } }, @@ -219,6 +230,7 @@ describe ('3ds Importer', function() { vertexColorCount: 0, normalCount: 12, uvCount: 8, + lineCount : 0, triangleCount: 12, boundingBox: { min: [ -1, 2, -1 ], max: [ 1, 4, 1 ] } }, @@ -228,6 +240,7 @@ describe ('3ds Importer', function() { vertexColorCount: 0, normalCount: 12, uvCount: 8, + lineCount : 0, triangleCount: 12, boundingBox: { min: [ -1, -1, 2 ], max: [ 1, 1, 4 ] } }, @@ -237,6 +250,7 @@ describe ('3ds Importer', function() { vertexColorCount: 0, normalCount: 12, uvCount: 8, + lineCount : 0, triangleCount: 12, boundingBox: { min: [ 2, -1, 2 ], max: [ 4, 1, 4 ] } }, @@ -246,6 +260,7 @@ describe ('3ds Importer', function() { vertexColorCount: 0, normalCount: 12, uvCount: 8, + lineCount : 0, triangleCount: 12, boundingBox: { min: [ 2, 2, 2 ], max: [ 4, 4, 4 ] } }, @@ -255,6 +270,7 @@ describe ('3ds Importer', function() { vertexColorCount: 0, normalCount: 12, uvCount: 8, + lineCount : 0, triangleCount: 12, boundingBox: { min: [ -1, 2, 2 ], max: [ 1, 4, 4 ] } } diff --git a/test/tests/importergltf_test.js b/test/tests/importergltf_test.js index 27d08e1..8892630 100644 --- a/test/tests/importergltf_test.js +++ b/test/tests/importergltf_test.js @@ -45,6 +45,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 1, uvCount : 0, + lineCount : 0, triangleCount : 1, boundingBox : { min : [0.0, 0.0, 0.0], @@ -102,6 +103,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 24, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [-0.5, -0.5, -0.5], @@ -158,6 +160,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 24, normalCount : 24, uvCount : 24, + lineCount : 0, triangleCount : 12, boundingBox : { min : [-0.5, -0.5, -0.5], @@ -214,6 +217,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 24, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [-0.5, -0.5, -0.5], @@ -270,6 +274,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 24, uvCount : 24, + lineCount : 0, triangleCount : 12, boundingBox : { min : [-0.5, -0.5, -0.5], @@ -324,6 +329,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 3, uvCount : 0, + lineCount : 0, triangleCount : 1, boundingBox : { min : [0.0, 0.0, 0.0], @@ -336,6 +342,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 3, uvCount : 0, + lineCount : 0, triangleCount : 1, boundingBox : { min : [1.0, 0.0, 0.0], @@ -381,7 +388,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 78, uvCount: 0, - triangleCount: 38, + lineCount : 0, + triangleCount : 38, boundingBox : { min: [ -0.6921195564310951, -1.0785199551363698, -5.330651201963446 ], max: [ 1.0439303242310798, 2.868914373727357, -4.66934876823423 ] @@ -393,7 +401,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 50, uvCount: 0, - triangleCount: 26, + lineCount : 0, + triangleCount : 26, boundingBox : { min: [ 0.8097413778305054, 2.8717148303985596, -5.33065128326416 ], max: [ 1.4936277866363525, 3.9211390018463135, -4.66934871673584 ] @@ -405,7 +414,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 50, uvCount: 0, - triangleCount: 26, + lineCount : 0, + triangleCount : 26, boundingBox : { min: [ -1.1686336994171143, -5.330650806427002, 2.93727445602417 ], max: [ -0.46912679076194763, -4.66934871673584, 3.9916374683380127 ] @@ -417,7 +427,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 78, uvCount: 0, - triangleCount: 38, + lineCount : 0, + triangleCount : 38, boundingBox : { min: [ -0.9557393651589479, -5.330651177643153, -1.06505742884149 ], max: [ 0.6167901044859734, -4.6693486435429055, 2.934442924096579 ] @@ -429,7 +440,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 78, uvCount: 0, - triangleCount: 38, + lineCount : 0, + triangleCount : 38, boundingBox : { min: [ -5.330651171390089, -1.0326269494863676, -0.6059335185163844 ], max: [ -4.669348828609911, 2.9885841671721116, 0.8202131194767724 ] @@ -441,7 +453,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 54, uvCount: 0, - triangleCount: 26, + lineCount : 0, + triangleCount : 26, boundingBox : { min: [ -5.33065128326416, 2.991360902786255, -0.012430161237716675 ], max: [ -4.66934871673584, 4.039160251617432, 0.6999828815460205 ] @@ -453,7 +466,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 52, uvCount: 0, - triangleCount: 26, + lineCount : 0, + triangleCount : 26, boundingBox : { min: [ -1.3648574352264404, 2.9005930423736572, 4.66934871673584 ], max: [ -0.6740907430648804, 3.9529545307159424, 5.33065128326416 ] @@ -465,7 +479,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 74, uvCount: 0, - triangleCount: 38, + lineCount : 0, + triangleCount : 38, boundingBox : { min: [ -1.009571011381568, -1.074115497823536, 4.669348895549774 ], max: [ 0.6625885973069405, 2.8977772707193465, 5.330651104450226 ] @@ -477,7 +492,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 54, uvCount: 0, - triangleCount: 26, + lineCount : 0, + triangleCount : 26, boundingBox : { min: [ 4.66934871673584, 2.4595587253570557, -2.553251266479492 ], max: [ 5.33065128326416, 3.432579517364502, -1.7226401567459106 ] @@ -489,7 +505,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 78, uvCount: 0, - triangleCount: 38, + lineCount : 0, + triangleCount : 38, boundingBox : { min: [ 4.669348835945129, -1.0589144181932033, -1.7207290818192755 ], max: [ 5.330651164054871, 2.4574561383341145, 0.9159925616542917 ] @@ -501,7 +518,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 52, uvCount: 0, - triangleCount: 26, + lineCount : 0, + triangleCount : 26, boundingBox : { min: [ 2.8218495845794678, 4.669349193572998, -1.6833229064941406 ], max: [ 3.864471435546875, 5.33065128326416, -1.0113166570663452 ] @@ -513,7 +531,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 78, uvCount: 0, - triangleCount: 38, + lineCount : 0, + triangleCount : 38, boundingBox : { min: [ -1.0826615032554154, 4.669348806142807, -1.093071740019906 ], max: [ 2.8190779754834807, 5.3306513130664825, 0.7348238365226794 ] @@ -525,7 +544,8 @@ describe ('Gltf Importer', function () { vertexColorCount: 0, normalCount: 272, uvCount: 0, - triangleCount: 140, + lineCount : 0, + triangleCount : 140, boundingBox : { min: [ -5.000001907348633, -5, -5.000001907348633 ], max: [ 5.000002384185791, 5, 5.000002861022949 ] @@ -566,6 +586,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 2, uvCount : 0, + lineCount : 0, triangleCount : 2, boundingBox : { min : [-0.5, -0.5, 0.0], @@ -603,6 +624,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 2, uvCount : 0, + lineCount : 0, triangleCount : 2, boundingBox : { min : [-0.5, -0.5, 0.0], @@ -641,6 +663,7 @@ describe ('Gltf Importer', function () { vertexColorCount : 0, normalCount : 12, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0.0, 0.0, 0.0], diff --git a/test/tests/importerobj_test.js b/test/tests/importerobj_test.js index 24ddaa8..3afec30 100644 --- a/test/tests/importerobj_test.js +++ b/test/tests/importerobj_test.js @@ -507,6 +507,7 @@ describe ('Obj Importer', function () { vertexColorCount : 0, normalCount : 6, uvCount : 4, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -537,6 +538,7 @@ describe ('Obj Importer', function () { vertexColorCount : 0, normalCount : 6, uvCount : 4, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -568,6 +570,7 @@ describe ('Obj Importer', function () { vertexColorCount : 0, normalCount : 6, uvCount : 4, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -599,6 +602,7 @@ describe ('Obj Importer', function () { vertexColorCount : 0, normalCount : 6, uvCount : 4, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -626,6 +630,7 @@ describe ('Obj Importer', function () { vertexColorCount : 0, normalCount : 20, uvCount : 0, + lineCount : 0, triangleCount : 20, boundingBox : { min : [-0.85065080835204, -0.85065080835204, -0.85065080835204], diff --git a/test/tests/importeroff_test.js b/test/tests/importeroff_test.js index 352f46d..b5e0d46 100644 --- a/test/tests/importeroff_test.js +++ b/test/tests/importeroff_test.js @@ -142,6 +142,7 @@ describe ('Off Importer', function () { vertexColorCount : 0, normalCount : 12, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], diff --git a/test/tests/importerply_test.js b/test/tests/importerply_test.js index 7e7e11d..68b2248 100644 --- a/test/tests/importerply_test.js +++ b/test/tests/importerply_test.js @@ -142,6 +142,7 @@ describe ('Ply Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -169,6 +170,7 @@ describe ('Ply Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -196,6 +198,7 @@ describe ('Ply Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -226,6 +229,7 @@ describe ('Ply Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], diff --git a/test/tests/importerstl_test.js b/test/tests/importerstl_test.js index ea28375..59fffbb 100644 --- a/test/tests/importerstl_test.js +++ b/test/tests/importerstl_test.js @@ -136,6 +136,7 @@ describe ('Stl Importer', function() { vertexColorCount : 0, normalCount : 572, uvCount : 0, + lineCount : 0, triangleCount : 572, boundingBox : { min : [0, -1.10792799192095, 0], @@ -163,6 +164,7 @@ describe ('Stl Importer', function() { vertexColorCount : 0, normalCount : 728, uvCount : 0, + lineCount : 0, triangleCount : 728, boundingBox : { min : [0, -1.1079280376434326, 0], @@ -191,6 +193,7 @@ describe ('Stl Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], @@ -218,6 +221,7 @@ describe ('Stl Importer', function() { vertexColorCount : 0, normalCount : 12, uvCount : 0, + lineCount : 0, triangleCount : 12, boundingBox : { min : [0, 0, 0], diff --git a/test/utils/testutils.js b/test/utils/testutils.js index b09b666..bf59856 100644 --- a/test/utils/testutils.js +++ b/test/utils/testutils.js @@ -162,6 +162,7 @@ export function ModelToObjectSimple (model) vertexColorCount : mesh.VertexColorCount (), normalCount : mesh.NormalCount (), uvCount : mesh.TextureUVCount (), + lineCount : mesh.LineSegmentCount (), triangleCount : mesh.TriangleCount (), boundingBox : { min : [boundingBox.min.x, boundingBox.min.y, boundingBox.min.z], From 0319fd4b326676c4b70fa73b104b37eea257dfce Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 24 Oct 2023 20:07:40 +0200 Subject: [PATCH 26/29] Correct line processing. --- source/engine/import/importerobj.js | 3 ++- test/testfiles/obj/lines_with_vt.obj | 11 ++++++++++ test/tests/importerobj_test.js | 33 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 test/testfiles/obj/lines_with_vt.obj diff --git a/source/engine/import/importerobj.js b/source/engine/import/importerobj.js index 839a6b4..897bcee 100644 --- a/source/engine/import/importerobj.js +++ b/source/engine/import/importerobj.js @@ -394,7 +394,8 @@ export class ImporterObj extends ImporterBase let vertices = []; for (let i = 0; i < parameters.length; i++) { - let vertexIndex = this.GetRelativeIndex (parseInt (parameters[i], 10), this.globalVertices.length); + let vertexParams = parameters[i].split ('/'); + let vertexIndex = this.GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length); let meshVertexIndex = this.currentMeshConverter.AddVertex (vertexIndex, this.globalVertices); if (meshVertexIndex === null) { this.SetError ('Invalid vertex index.'); diff --git a/test/testfiles/obj/lines_with_vt.obj b/test/testfiles/obj/lines_with_vt.obj new file mode 100644 index 0000000..c3545ba --- /dev/null +++ b/test/testfiles/obj/lines_with_vt.obj @@ -0,0 +1,11 @@ +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 1.0 1.0 0.0 +v 0.0 1.0 0.0 +v 0.0 0.0 1.0 +v 1.0 0.0 1.0 +v 1.0 1.0 1.0 +v 0.0 1.0 1.0 +l 1/1 2/2 +l 3/3 4/4 +l 5/5 6/6 7/7 8/8 5/5 diff --git a/test/tests/importerobj_test.js b/test/tests/importerobj_test.js index 3afec30..b636a08 100644 --- a/test/tests/importerobj_test.js +++ b/test/tests/importerobj_test.js @@ -685,6 +685,39 @@ describe ('Obj Importer', function () { }); }); + it ('lines_with_vt.obj', function (done) { + ImportObjFile ('lines_with_vt.obj', function (model) { + assert.ok (OV.CheckModel (model)); + assert.deepStrictEqual (ModelToObject (model), { + name : '', + materials : [ + { name : '' } + ], + meshes : [ + { + name : '', + lines : [ + { + vertices : [0, 0, 0, 1, 0, 0], + mat : 0 + }, + { + vertices : [1, 1, 0, 0, 1, 0], + mat : 0 + }, + { + vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1], + mat : 0 + } + ], + triangles : [] + } + ] + }); + done (); + }); + }); + it ('lines_in_meshes.obj', function (done) { ImportObjFile ('lines_in_meshes.obj', function (model) { assert.ok (OV.CheckModel (model)); From f83d5f02f57c3f46fbcf4add8dd988ae4c35d24e Mon Sep 17 00:00:00 2001 From: kovacsv Date: Wed, 25 Oct 2023 21:37:04 +0200 Subject: [PATCH 27/29] Add heuristics for line threshold during ray casting. --- source/engine/viewer/viewermodel.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/engine/viewer/viewermodel.js b/source/engine/viewer/viewermodel.js index 15c8781..4c951ba 100644 --- a/source/engine/viewer/viewermodel.js +++ b/source/engine/viewer/viewermodel.js @@ -301,7 +301,12 @@ export class ViewerMainModel } let raycaster = new THREE.Raycaster (); - raycaster.params.Line.threshold = 0.1; + if (this.hasLines) { + let boundingSphere = this.GetBoundingSphere (() => { + return true; + }); + raycaster.params.Line.threshold = boundingSphere.radius / 100.0; + } let mousePos = new THREE.Vector2 (); mousePos.x = (mouseCoords.x / width) * 2 - 1; From 8b3092acda0534ce949aa2a1852649c28faacf8a Mon Sep 17 00:00:00 2001 From: kovacsv Date: Wed, 25 Oct 2023 21:39:37 +0200 Subject: [PATCH 28/29] Import lines from 3dm files. --- source/engine/import/importer3dm.js | 97 ++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 22 deletions(-) diff --git a/source/engine/import/importer3dm.js b/source/engine/import/importer3dm.js index 1da0ba1..4b5278e 100644 --- a/source/engine/import/importer3dm.js +++ b/source/engine/import/importer3dm.js @@ -11,6 +11,9 @@ import { ConvertThreeGeometryToMesh } from '../threejs/threeutils.js'; import { ImporterBase } from './importerbase.js'; import { UpdateMaterialTransparency } from './importerutils.js'; import { TextureMap } from '../model/material.js'; +import { Mesh } from '../model/mesh.js'; +import { Line } from '../model/line.js'; +import { ArrayToCoord3D } from '../geometry/coord3d.js'; export class Importer3dm extends ImporterBase { @@ -130,17 +133,16 @@ export class Importer3dm extends ImporterBase return; } - let rhinoMesh = null; - let deleteMesh = false; - if (objectType === this.rhino.ObjectType.Mesh) { - rhinoMesh = rhinoGeometry; - deleteMesh = false; + this.ImportRhinoGeometryAsMesh (rhinoDoc, rhinoGeometry, rhinoObject, rhinoInstanceReferences); } else if (objectType === this.rhino.ObjectType.Extrusion) { - rhinoMesh = rhinoGeometry.getMesh (this.rhino.MeshType.Any); - deleteMesh = true; + let rhinoMesh = rhinoGeometry.getMesh (this.rhino.MeshType.Any); + if (rhinoMesh !== null) { + this.ImportRhinoGeometryAsMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences); + rhinoMesh.delete (); + } } else if (objectType === this.rhino.ObjectType.Brep) { - rhinoMesh = new this.rhino.Mesh (); + let rhinoMesh = new this.rhino.Mesh (); let faces = rhinoGeometry.faces (); for (let i = 0; i < faces.count; i++) { let face = faces.get (i); @@ -153,11 +155,17 @@ export class Importer3dm extends ImporterBase } faces.delete (); rhinoMesh.compact (); - deleteMesh = true; + this.ImportRhinoGeometryAsMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences); + rhinoMesh.delete (); } else if (objectType === this.rhino.ObjectType.SubD) { rhinoGeometry.subdivide (3); - rhinoMesh = this.rhino.Mesh.createFromSubDControlNet (rhinoGeometry); - deleteMesh = true; + let rhinoMesh = this.rhino.Mesh.createFromSubDControlNet (rhinoGeometry); + if (rhinoMesh !== null) { + this.ImportRhinoGeometryAsMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences); + rhinoMesh.delete (); + } + } else if (objectType === this.rhino.ObjectType.Curve) { + this.ImportRhinoGeometryAsMesh (rhinoDoc, rhinoGeometry, rhinoObject, rhinoInstanceReferences); } else if (objectType === this.rhino.ObjectType.InstanceReference) { let parentDefinitionId = rhinoGeometry.parentIdefId; if (this.instanceIdToDefinition.has (parentDefinitionId)) { @@ -174,22 +182,58 @@ export class Importer3dm extends ImporterBase } } } - - if (rhinoMesh !== null) { - this.ImportRhinoMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences); - if (deleteMesh) { - rhinoMesh.delete (); - } - } } - ImportRhinoMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences) + ImportRhinoGeometryAsMesh (rhinoDoc, rhinoGeometry, rhinoObject, rhinoInstanceReferences) { - let rhinoAttributes = rhinoObject.attributes (); + function GetSegmentedCurveLine (curveGeometry) + { + let domainLength = curveGeometry.domain[1] - curveGeometry.domain[0]; + let segmentCount = Math.max (parseInt (domainLength / 0.2, 10), 1); + let segmentLength = domainLength / segmentCount; + let vertices = []; + for (let i = 0; i <= segmentCount; i++) { + if (i === segmentCount && curveGeometry.isClosed) { + vertices.push (vertices[0]); + } else { + let position = rhinoGeometry.pointAt (curveGeometry.domain[0] + i * segmentLength); + vertices.push (mesh.AddVertex (ArrayToCoord3D (position))); + } + } + return new Line (vertices); + } let materialIndex = this.GetMaterialIndex (rhinoDoc, rhinoObject, rhinoInstanceReferences); - let threeJson = rhinoMesh.toThreejsJSON (); - let mesh = ConvertThreeGeometryToMesh (threeJson.data, materialIndex, null); + let mesh = null; + if (rhinoGeometry.objectType === this.rhino.ObjectType.Mesh) { + let threeJson = rhinoGeometry.toThreejsJSON (); + mesh = ConvertThreeGeometryToMesh (threeJson.data, materialIndex, null); + } else if (rhinoGeometry.objectType === this.rhino.ObjectType.Curve) { + mesh = new Mesh (); + if (rhinoGeometry instanceof this.rhino.LineCurve) { + let fromVertex = mesh.AddVertex (ArrayToCoord3D (rhinoGeometry.line.from)); + let toVertex = mesh.AddVertex (ArrayToCoord3D (rhinoGeometry.line.to)); + let line = new Line ([fromVertex, toVertex]); + line.SetMaterial (materialIndex); + mesh.AddLine (line); + } else if (rhinoGeometry instanceof this.rhino.NurbsCurve) { + let line = GetSegmentedCurveLine (rhinoGeometry); + line.SetMaterial (materialIndex); + mesh.AddLine (line); + } else if (rhinoGeometry instanceof this.rhino.ArcCurve) { + let line = GetSegmentedCurveLine (rhinoGeometry); + line.SetMaterial (materialIndex); + mesh.AddLine (line); + } + } + + // TODO: BezierCurve, PolyCurve + + if (mesh === null) { + return null; + } + + let rhinoAttributes = rhinoObject.attributes (); mesh.SetName (rhinoAttributes.name); let userStrings = rhinoAttributes.getUserStrings (); @@ -234,6 +278,15 @@ export class Importer3dm extends ImporterBase let layerMaterialIndex = layer.renderMaterialIndex; if (layerMaterialIndex > -1) { return rhinoDoc.materials ().get (layerMaterialIndex); + } else { + // use layer color only in case of curves + let rhinoGeometry = rhinoObject.geometry (); + if (rhinoGeometry.objectType === rhino.ObjectType.Curve) { + let material = new rhino.Material (); + material.name = layer.name; + material.diffuseColor = layer.color; + return material; + } } } } else if (rhinoAttributes.materialSource === rhino.ObjectMaterialSource.MaterialFromParent) { From 3022673c5ea655dfacecba70aedf5cfe392339f8 Mon Sep 17 00:00:00 2001 From: Viktor Kovacs Date: Fri, 27 Oct 2023 11:47:42 +0200 Subject: [PATCH 29/29] Add new line threshold calculation algorithm. --- source/engine/viewer/viewermodel.js | 44 +++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/source/engine/viewer/viewermodel.js b/source/engine/viewer/viewermodel.js index 4c951ba..b8454cf 100644 --- a/source/engine/viewer/viewermodel.js +++ b/source/engine/viewer/viewermodel.js @@ -121,6 +121,7 @@ export class ViewerMainModel this.edgeSettings = new EdgeSettings (false, new RGBColor (0, 0, 0), 1); this.hasLines = false; this.hasPolygonOffset = false; + this.fullBoundingBox = null; } SetMainObject (mainObject) @@ -128,6 +129,7 @@ export class ViewerMainModel this.mainModel.SetRootObject (mainObject); this.hasLines = false; this.hasPolygonOffset = false; + this.fullBoundingBox = null; this.EnumerateLines ((line) => { this.hasLines = true; @@ -192,6 +194,17 @@ export class ViewerMainModel this.UpdatePolygonOffset (); } + GetFullBoundingBox () + { + if (this.fullBoundingBox !== null) { + return this.fullBoundingBox; + } + this.fullBoundingBox = this.GetBoundingBox (() => { + return true; + }); + return this.fullBoundingBox; + } + GetBoundingBox (needToProcess) { let hasMesh = false; @@ -292,6 +305,18 @@ export class ViewerMainModel GetMeshIntersectionUnderMouse (mouseCoords, camera, width, height) { + function CalculateLineThreshold (mousePos, camera, boundingBoxCenter) + { + let thresholdInScreenCoordinates = 15.0; + let frustumRange = camera.far - camera.near; + let cameraDistanceFromCenter = boundingBoxCenter.distanceTo (camera.position); + let distanceInFrustumRatio = cameraDistanceFromCenter / frustumRange; + let zValue = -1.0 + 2.0 * distanceInFrustumRatio; + let referencePoint1 = new THREE.Vector3 (mousePos.x, mousePos.y, zValue).unproject (camera); + let referencePoint2 = new THREE.Vector3 (mousePos.x + thresholdInScreenCoordinates, mousePos.y, zValue).unproject (camera); + return referencePoint1.distanceTo (referencePoint2); + } + if (this.mainModel.IsEmpty ()) { return null; } @@ -300,17 +325,20 @@ export class ViewerMainModel return null; } - let raycaster = new THREE.Raycaster (); - if (this.hasLines) { - let boundingSphere = this.GetBoundingSphere (() => { - return true; - }); - raycaster.params.Line.threshold = boundingSphere.radius / 100.0; - } - let mousePos = new THREE.Vector2 (); mousePos.x = (mouseCoords.x / width) * 2 - 1; mousePos.y = -(mouseCoords.y / height) * 2 + 1; + + let raycaster = new THREE.Raycaster (); + if (this.hasLines) { + let boundingBox = this.GetFullBoundingBox (); + if (boundingBox !== null) { + let boundingBoxCenter = new THREE.Vector3 (0.0, 0.0, 0.0); + boundingBox.getCenter (boundingBoxCenter); + raycaster.params.Line.threshold = CalculateLineThreshold (mousePos, camera, boundingBoxCenter); + } + } + raycaster.setFromCamera (mousePos, camera); let iSectObjects = raycaster.intersectObject (this.mainModel.GetRootObject (), true); for (let i = 0; i < iSectObjects.length; i++) {