mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: improve gltf handling
- scene
- write with fileName, additional getMesh accessor
- addColourToMesh accepts an alpha field size 1 as a constant
alpha value
- sceneWriter wrapper
ENH: improve gltf handling of colour and alpha specification
- accept plain input directly.
Eg,
colour (1 0 1);
vs
colour uniform;
colourValue (1 0 1);
- use field magnitude for colouring of non-scalar fields.
Eg, having three different colour maps for a vector field simply
does not help much with visualisation.
This commit is contained in:
@ -36,6 +36,7 @@ gltf/foamGltfBufferView.C
|
|||||||
gltf/foamGltfMesh.C
|
gltf/foamGltfMesh.C
|
||||||
gltf/foamGltfObject.C
|
gltf/foamGltfObject.C
|
||||||
gltf/foamGltfScene.C
|
gltf/foamGltfScene.C
|
||||||
|
gltf/foamGltfSceneWriter.C
|
||||||
|
|
||||||
starcd/STARCDCore.C
|
starcd/STARCDCore.C
|
||||||
stl/STLCore.C
|
stl/STLCore.C
|
||||||
|
|||||||
@ -178,7 +178,7 @@ public:
|
|||||||
//- Predefined tables
|
//- Predefined tables
|
||||||
static const HashPtrTable<colourTable>& tables();
|
static const HashPtrTable<colourTable>& tables();
|
||||||
|
|
||||||
//- Return the colour at x (within 0-1 range)
|
//- Return the colour at x. The input is clipped to 0-1 range.
|
||||||
vector value(const scalar x) const;
|
vector value(const scalar x) const;
|
||||||
|
|
||||||
//- Return a discrete lookup table of colours
|
//- Return a discrete lookup table of colours
|
||||||
|
|||||||
54
src/fileFormats/gltf/foamGltfFwd.H
Normal file
54
src/fileFormats/gltf/foamGltfFwd.H
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM.
|
||||||
|
|
||||||
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Description
|
||||||
|
Forward declarations for exposed glTF interfaces
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef Foam_gltf_Forward_Declarations_H
|
||||||
|
#define Foam_gltf_Forward_Declarations_H
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace glTF
|
||||||
|
{
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
class scene;
|
||||||
|
class sceneWriter;
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace glTF
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -28,15 +28,14 @@ License
|
|||||||
template<class Type>
|
template<class Type>
|
||||||
void Foam::glTF::object::addData(const Type& fld)
|
void Foam::glTF::object::addData(const Type& fld)
|
||||||
{
|
{
|
||||||
const label nComponents =
|
const direction nCmpts = pTraits<typename Type::value_type>::nComponents;
|
||||||
pTraits<typename Type::value_type>::nComponents;
|
|
||||||
|
|
||||||
label count = data_.size();
|
label count = data_.size();
|
||||||
data_.setSize(data_.size() + fld.size()*nComponents);
|
data_.resize(data_.size() + fld.size()*nCmpts);
|
||||||
|
|
||||||
forAll(fld, fieldi)
|
forAll(fld, fieldi)
|
||||||
{
|
{
|
||||||
for (direction d = 0; d < nComponents; ++d)
|
for (direction d = 0; d < nCmpts; ++d)
|
||||||
{
|
{
|
||||||
data_[count++] = component(fld[fieldi], d);
|
data_[count++] = component(fld[fieldi], d);
|
||||||
}
|
}
|
||||||
@ -55,26 +54,20 @@ void Foam::glTF::object::addData(const Type1& fld1, const Type2&fld2)
|
|||||||
<< abort(FatalError);
|
<< abort(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const label nComponents1 =
|
const direction nCmpts1 = pTraits<typename Type1::value_type>::nComponents;
|
||||||
pTraits<typename Type1::value_type>::nComponents;
|
const direction nCmpts2 = pTraits<typename Type2::value_type>::nComponents;
|
||||||
|
|
||||||
const label nComponents2 =
|
|
||||||
pTraits<typename Type2::value_type>::nComponents;
|
|
||||||
|
|
||||||
label count = data_.size();
|
label count = data_.size();
|
||||||
data_.setSize
|
data_.resize(data_.size() + fld1.size()*(nCmpts1 + nCmpts2));
|
||||||
(
|
|
||||||
data_.size() + fld1.size()*(nComponents1 + nComponents2)
|
|
||||||
);
|
|
||||||
|
|
||||||
forAll(fld1, fieldi)
|
forAll(fld1, fieldi)
|
||||||
{
|
{
|
||||||
for (direction d = 0; d < nComponents1; ++d)
|
for (direction d = 0; d < nCmpts1; ++d)
|
||||||
{
|
{
|
||||||
data_[count++] = component(fld1[fieldi], d);
|
data_[count++] = component(fld1[fieldi], d);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (direction d = 0; d < nComponents2; ++d)
|
for (direction d = 0; d < nCmpts2; ++d)
|
||||||
{
|
{
|
||||||
data_[count++] = component(fld2[fieldi], d);
|
data_[count++] = component(fld2[fieldi], d);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2021 OpenCFD Ltd.
|
Copyright (C) 2021-2022 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -26,7 +26,8 @@ License
|
|||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "foamGltfScene.H"
|
#include "foamGltfScene.H"
|
||||||
#include "fileName.H"
|
#include "OFstream.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -43,6 +44,26 @@ Foam::glTF::scene::scene()
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::glTF::mesh& Foam::glTF::scene::getMesh(label meshi)
|
||||||
|
{
|
||||||
|
const label lastMeshi = (meshes_.size() - 1);
|
||||||
|
|
||||||
|
if (meshi < 0)
|
||||||
|
{
|
||||||
|
meshi = (lastMeshi < 0 ? static_cast<label>(0) : lastMeshi);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meshi > lastMeshi)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Mesh " << meshi << " out of range: " << lastMeshi
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return meshes_[meshi];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Foam::label Foam::glTF::scene::addColourToMesh
|
Foam::label Foam::glTF::scene::addColourToMesh
|
||||||
(
|
(
|
||||||
const vectorField& fld,
|
const vectorField& fld,
|
||||||
@ -51,13 +72,7 @@ Foam::label Foam::glTF::scene::addColourToMesh
|
|||||||
const scalarField& alpha
|
const scalarField& alpha
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (meshi > meshes_.size() - 1)
|
auto& gmesh = getMesh(meshi);
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Mesh " << meshi << " out of range "
|
|
||||||
<< (meshes_.size() - 1)
|
|
||||||
<< abort(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& bv = bufferViews_.create(name);
|
auto& bv = bufferViews_.create(name);
|
||||||
bv.byteOffset() = bytes_;
|
bv.byteOffset() = bytes_;
|
||||||
@ -71,21 +86,29 @@ Foam::label Foam::glTF::scene::addColourToMesh
|
|||||||
|
|
||||||
auto& obj = objects_.create(name);
|
auto& obj = objects_.create(name);
|
||||||
|
|
||||||
if (alpha.size())
|
if (alpha.empty())
|
||||||
|
{
|
||||||
|
obj.addData(fld);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
bv.byteLength() += fld.size()*sizeof(float);
|
bv.byteLength() += fld.size()*sizeof(float);
|
||||||
bytes_ += fld.size()*sizeof(float);
|
bytes_ += fld.size()*sizeof(float);
|
||||||
|
|
||||||
acc.type() = "VEC4";
|
acc.type() = "VEC4";
|
||||||
|
|
||||||
obj.addData(fld, alpha);
|
// Support uniform alpha vs full alpha field
|
||||||
}
|
tmp<scalarField> talpha(alpha);
|
||||||
else
|
|
||||||
|
if (alpha.size() == 1 && alpha.size() < fld.size())
|
||||||
{
|
{
|
||||||
obj.addData(fld);
|
talpha = tmp<scalarField>::New(fld.size(), alpha[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
meshes_[meshi].addColour(acc.id());
|
obj.addData(fld, talpha());
|
||||||
|
}
|
||||||
|
|
||||||
|
gmesh.addColour(acc.id());
|
||||||
|
|
||||||
return acc.id();
|
return acc.id();
|
||||||
}
|
}
|
||||||
@ -136,13 +159,27 @@ void Foam::glTF::scene::addToAnimation
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::glTF::scene::write(const fileName& outputFile)
|
||||||
|
{
|
||||||
|
fileName jsonFile(outputFile.lessExt());
|
||||||
|
jsonFile.ext("gltf");
|
||||||
|
|
||||||
|
// Note: called on master only
|
||||||
|
|
||||||
|
if (!isDir(jsonFile.path()))
|
||||||
|
{
|
||||||
|
mkDir(jsonFile.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
OFstream os(jsonFile);
|
||||||
|
write(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::glTF::scene::write(Ostream& os)
|
void Foam::glTF::scene::write(Ostream& os)
|
||||||
{
|
{
|
||||||
const fileName base(os.name().lessExt());
|
fileName binFile(os.name().lessExt());
|
||||||
const fileName binFile
|
binFile.ext("bin");
|
||||||
(
|
|
||||||
fileName::concat(base.path(), fileName::name(base) + ".bin")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Write binary file
|
// Write binary file
|
||||||
// Note: using stdStream
|
// Note: using stdStream
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2021 OpenCFD Ltd.
|
Copyright (C) 2021-2022 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -38,9 +38,10 @@ SourceFiles
|
|||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef foam_gltf_scene_H
|
#ifndef Foam_gltf_scene_H
|
||||||
#define foam_gltf_scene_H
|
#define Foam_gltf_scene_H
|
||||||
|
|
||||||
|
#include "fileName.H"
|
||||||
#include "foamGltfList.H"
|
#include "foamGltfList.H"
|
||||||
#include "foamGltfObject.H"
|
#include "foamGltfObject.H"
|
||||||
#include "foamGltfMesh.H"
|
#include "foamGltfMesh.H"
|
||||||
@ -49,12 +50,15 @@ SourceFiles
|
|||||||
#include "foamGltfAnimation.H"
|
#include "foamGltfAnimation.H"
|
||||||
#include "scalarField.H"
|
#include "scalarField.H"
|
||||||
#include "vectorField.H"
|
#include "vectorField.H"
|
||||||
#include "OFstream.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
class OFstream;
|
||||||
|
|
||||||
namespace glTF
|
namespace glTF
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -85,6 +89,13 @@ class scene
|
|||||||
label bytes_;
|
label bytes_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Member Functions
|
||||||
|
|
||||||
|
//- Non-const access to mesh at index (can be -1 for last mesh)
|
||||||
|
// FatalError for out-of-bounds
|
||||||
|
mesh& getMesh(label meshi);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
@ -114,16 +125,19 @@ public:
|
|||||||
(
|
(
|
||||||
const Type& fld,
|
const Type& fld,
|
||||||
const word& name,
|
const word& name,
|
||||||
const label meshi
|
const label meshId
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Returns accessor index
|
//- Add a colour field to the mesh, optionally with an alpha channel.
|
||||||
|
// A constant alpha value can be specified as a field of size 1.
|
||||||
|
//
|
||||||
|
// \returns accessor index
|
||||||
label addColourToMesh
|
label addColourToMesh
|
||||||
(
|
(
|
||||||
const vectorField& fld,
|
const vectorField& fld, //!< RGB colour field
|
||||||
const word& name,
|
const word& name,
|
||||||
const label meshi,
|
const label meshId,
|
||||||
const scalarField& alpha = scalarField()
|
const scalarField& alpha = scalarField::null() //!< Alpha channel
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Returns index of last animation
|
//- Returns index of last animation
|
||||||
@ -139,7 +153,13 @@ public:
|
|||||||
const string& interpolation = "LINEAR"
|
const string& interpolation = "LINEAR"
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Write to stream (JSON and binary data)
|
|
||||||
|
// Write
|
||||||
|
|
||||||
|
//- Write to file pair (.gltf, .bin)
|
||||||
|
void write(const fileName& outputFile);
|
||||||
|
|
||||||
|
//- Write JSON (.gltf) to stream with auxiliary binary data (.bin)
|
||||||
void write(Ostream& os);
|
void write(Ostream& os);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -33,11 +33,11 @@ Foam::label Foam::glTF::scene::addField
|
|||||||
const label target
|
const label target
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const label nComponents = pTraits<typename Type::value_type>::nComponents;
|
const direction nCmpts = pTraits<typename Type::value_type>::nComponents;
|
||||||
|
|
||||||
auto& bv = bufferViews_.create(name);
|
auto& bv = bufferViews_.create(name);
|
||||||
bv.byteOffset() = bytes_;
|
bv.byteOffset() = bytes_;
|
||||||
bv.byteLength() = fld.size()*nComponents*sizeof(float);
|
bv.byteLength() = fld.size()*nCmpts*sizeof(float);
|
||||||
if (target != -1)
|
if (target != -1)
|
||||||
{
|
{
|
||||||
bv.target() = target;
|
bv.target() = target;
|
||||||
@ -61,8 +61,8 @@ Foam::label Foam::glTF::scene::addMesh(const Type& fld, const word& name)
|
|||||||
const label accessorId =
|
const label accessorId =
|
||||||
addField(fld, name, key(targetTypes::ARRAY_BUFFER));
|
addField(fld, name, key(targetTypes::ARRAY_BUFFER));
|
||||||
|
|
||||||
auto& mesh = meshes_.create(name);
|
auto& gmesh = meshes_.create(name);
|
||||||
mesh.accessorId() = accessorId;
|
gmesh.accessorId() = accessorId;
|
||||||
|
|
||||||
return meshes_.size() - 1;
|
return meshes_.size() - 1;
|
||||||
}
|
}
|
||||||
@ -76,17 +76,11 @@ Foam::label Foam::glTF::scene::addFieldToMesh
|
|||||||
const label meshi
|
const label meshi
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (meshi > meshes_.size() - 1)
|
auto& gmesh = getMesh(meshi);
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Mesh " << meshi << " out of range "
|
|
||||||
<< (meshes_.size() - 1)
|
|
||||||
<< abort(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
const label accessorId = addField(fld, name);
|
const label accessorId = addField(fld, name);
|
||||||
|
|
||||||
meshes_[meshi].addField(name, accessorId);
|
gmesh.addField(name, accessorId);
|
||||||
|
|
||||||
return accessorId;
|
return accessorId;
|
||||||
}
|
}
|
||||||
|
|||||||
106
src/fileFormats/gltf/foamGltfSceneWriter.C
Normal file
106
src/fileFormats/gltf/foamGltfSceneWriter.C
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM.
|
||||||
|
|
||||||
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "foamGltfSceneWriter.H"
|
||||||
|
#include "OFstream.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::glTF::sceneWriter::sceneWriter(const fileName& outputFile)
|
||||||
|
:
|
||||||
|
ofile_(nullptr),
|
||||||
|
scene_(nullptr)
|
||||||
|
{
|
||||||
|
open(outputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::glTF::sceneWriter::~sceneWriter()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
bool Foam::glTF::sceneWriter::valid() const noexcept
|
||||||
|
{
|
||||||
|
return (ofile_ && scene_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Foam::fileName& Foam::glTF::sceneWriter::path() const
|
||||||
|
{
|
||||||
|
return (ofile_ ? ofile_->name() : fileName::null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Foam::glTF::scene& Foam::glTF::sceneWriter::getScene() const
|
||||||
|
{
|
||||||
|
return *scene_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::glTF::scene& Foam::glTF::sceneWriter::getScene()
|
||||||
|
{
|
||||||
|
return *scene_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::glTF::sceneWriter::open(const fileName& outputFile)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
|
||||||
|
fileName jsonFile(outputFile.lessExt());
|
||||||
|
jsonFile.ext("gltf");
|
||||||
|
|
||||||
|
// Note: called on master only
|
||||||
|
if (!isDir(jsonFile.path()))
|
||||||
|
{
|
||||||
|
mkDir(jsonFile.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
ofile_.reset(new OFstream(jsonFile));
|
||||||
|
scene_.reset(new glTF::scene());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::glTF::sceneWriter::close()
|
||||||
|
{
|
||||||
|
if (ofile_ && scene_)
|
||||||
|
{
|
||||||
|
scene_->write(*ofile_);
|
||||||
|
}
|
||||||
|
ofile_.reset(nullptr);
|
||||||
|
scene_.reset(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
126
src/fileFormats/gltf/foamGltfSceneWriter.H
Normal file
126
src/fileFormats/gltf/foamGltfSceneWriter.H
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM.
|
||||||
|
|
||||||
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::glTF::sceneWriter
|
||||||
|
|
||||||
|
Description
|
||||||
|
Wrapper for glTF scene for file output
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
foamGltfSceneWriter.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef Foam_gltf_sceneWriter_H
|
||||||
|
#define Foam_gltf_sceneWriter_H
|
||||||
|
|
||||||
|
#include "autoPtr.H"
|
||||||
|
#include "fileName.H"
|
||||||
|
#include "foamGltfScene.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
class OFstream;
|
||||||
|
|
||||||
|
namespace glTF
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class glTF::sceneWriter Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class sceneWriter
|
||||||
|
{
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- The backend output stream (json)
|
||||||
|
autoPtr<OFstream> ofile_;
|
||||||
|
|
||||||
|
//- The scene to output
|
||||||
|
autoPtr<glTF::scene> scene_;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Generated Methods
|
||||||
|
|
||||||
|
//- No copy construct
|
||||||
|
sceneWriter(const sceneWriter&) = delete;
|
||||||
|
|
||||||
|
//- No copy assignment
|
||||||
|
void operator=(const sceneWriter&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Default construct
|
||||||
|
sceneWriter() = default;
|
||||||
|
|
||||||
|
//- Construct and open with given file name
|
||||||
|
explicit sceneWriter(const fileName& outputFile);
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor - calls close()
|
||||||
|
~sceneWriter();
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- True if output file and scene exist
|
||||||
|
bool valid() const noexcept;
|
||||||
|
|
||||||
|
//- The json file name. Empty with !valid()
|
||||||
|
const fileName& path() const;
|
||||||
|
|
||||||
|
//- Const access to the scene. Error if valid() is not true!
|
||||||
|
const scene& getScene() const;
|
||||||
|
|
||||||
|
//- Non-const access to the scene. Error if valid() is not true!
|
||||||
|
scene& getScene();
|
||||||
|
|
||||||
|
|
||||||
|
//- Flush, output and open a new file for output
|
||||||
|
void open(const fileName& outputFile);
|
||||||
|
|
||||||
|
//- Write scene and close file
|
||||||
|
void close();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace glTF
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2021 OpenCFD Ltd.
|
Copyright (C) 2021-2022 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -39,6 +39,7 @@ template<class Type>
|
|||||||
const Foam::Enum<typename Foam::gltfSetWriter<Type>::fieldOption>
|
const Foam::Enum<typename Foam::gltfSetWriter<Type>::fieldOption>
|
||||||
Foam::gltfSetWriter<Type>::fieldOptionNames_
|
Foam::gltfSetWriter<Type>::fieldOptionNames_
|
||||||
({
|
({
|
||||||
|
// No naming for NONE
|
||||||
{ fieldOption::UNIFORM, "uniform" },
|
{ fieldOption::UNIFORM, "uniform" },
|
||||||
{ fieldOption::FIELD, "field" },
|
{ fieldOption::FIELD, "field" },
|
||||||
});
|
});
|
||||||
@ -70,26 +71,19 @@ const Foam::colourTable& Foam::gltfSetWriter<Type>::getColourTable
|
|||||||
|
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
Foam::scalar Foam::gltfSetWriter<Type>::getFieldMin
|
Foam::scalarMinMax Foam::gltfSetWriter<Type>::getFieldLimits
|
||||||
(
|
(
|
||||||
const word& fieldName
|
const word& fieldName
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
const dictionary fieldDict = fieldInfoDict_.subOrEmptyDict(fieldName);
|
const dictionary fieldDict = fieldInfoDict_.subOrEmptyDict(fieldName);
|
||||||
|
|
||||||
return fieldDict.getOrDefault("min", -GREAT);
|
scalarMinMax limits;
|
||||||
}
|
|
||||||
|
|
||||||
|
fieldDict.readIfPresent("min", limits.min());
|
||||||
|
fieldDict.readIfPresent("max", limits.max());
|
||||||
|
|
||||||
template<class Type>
|
return limits;
|
||||||
Foam::scalar Foam::gltfSetWriter<Type>::getFieldMax
|
|
||||||
(
|
|
||||||
const word& fieldName
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
const dictionary fieldDict = fieldInfoDict_.subOrEmptyDict(fieldName);
|
|
||||||
|
|
||||||
return fieldDict.getOrDefault("max", GREAT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -101,69 +95,39 @@ Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getAlphaField
|
|||||||
const List<const Field<Type>*>& valueSets
|
const List<const Field<Type>*>& valueSets
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
if (dict.found("alpha"))
|
// Fallback value
|
||||||
|
scalar alphaValue(1);
|
||||||
|
|
||||||
|
const entry* eptr = dict.findEntry("alpha", keyType::LITERAL);
|
||||||
|
|
||||||
|
if (!eptr)
|
||||||
{
|
{
|
||||||
|
// Not specified
|
||||||
|
}
|
||||||
|
else if (!eptr->stream().peek().isString())
|
||||||
|
{
|
||||||
|
// Value specified
|
||||||
|
|
||||||
|
ITstream& is = eptr->stream();
|
||||||
|
is >> alphaValue;
|
||||||
|
dict.checkITstream(is, "alpha");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Enumeration
|
||||||
|
|
||||||
const auto option = fieldOptionNames_.get("alpha", dict);
|
const auto option = fieldOptionNames_.get("alpha", dict);
|
||||||
|
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
|
case fieldOption::NONE:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
case fieldOption::UNIFORM:
|
case fieldOption::UNIFORM:
|
||||||
{
|
{
|
||||||
const scalar value = dict.getScalar("alphaValue");
|
dict.readEntry("alphaValue", alphaValue);
|
||||||
return tmp<scalarField>::New(valueSets[0]->size(), value);
|
break;
|
||||||
}
|
|
||||||
case fieldOption::FIELD:
|
|
||||||
{
|
|
||||||
const word alphaFieldName = dict.get<word>("alphaField");
|
|
||||||
const bool normalise = dict.get<bool>("normalise");
|
|
||||||
const label i = valueSetNames.find(alphaFieldName);
|
|
||||||
if (i == -1)
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Unable to find field " << alphaFieldName
|
|
||||||
<< ". Valid field names are:" << valueSetNames
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tresult =
|
|
||||||
tmp<scalarField>::New(valueSets[i]->component(0));
|
|
||||||
|
|
||||||
if (normalise)
|
|
||||||
{
|
|
||||||
tresult.ref() /= mag(tresult() + ROOTVSMALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tresult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmp<scalarField>::New(valueSets[0]->size(), Zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getTrackAlphaField
|
|
||||||
(
|
|
||||||
const dictionary& dict,
|
|
||||||
const wordList& valueSetNames,
|
|
||||||
const List<List<Field<Type>>>& valueSets,
|
|
||||||
const label tracki
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
if (dict.found("alpha"))
|
|
||||||
{
|
|
||||||
const auto option = fieldOptionNames_.get("alpha", dict);
|
|
||||||
|
|
||||||
switch (option)
|
|
||||||
{
|
|
||||||
case fieldOption::UNIFORM:
|
|
||||||
{
|
|
||||||
const scalar value = dict.getScalar("alphaValue");
|
|
||||||
return tmp<scalarField>::New
|
|
||||||
(
|
|
||||||
valueSets[0][tracki].size(), value
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
case fieldOption::FIELD:
|
case fieldOption::FIELD:
|
||||||
{
|
{
|
||||||
@ -178,12 +142,9 @@ Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getTrackAlphaField
|
|||||||
<< exit(FatalError);
|
<< exit(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: selecting the first component!
|
const Field<Type>& alphaFld = *(valueSets[fieldi]);
|
||||||
auto tresult =
|
|
||||||
tmp<scalarField>::New
|
auto tresult = tmp<scalarField>::New(alphaFld.component(0));
|
||||||
(
|
|
||||||
valueSets[fieldi][tracki].component(0)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (normalise)
|
if (normalise)
|
||||||
{
|
{
|
||||||
@ -195,7 +156,82 @@ Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getTrackAlphaField
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmp<scalarField>::New(valueSets[0][tracki].size(), Zero);
|
return tmp<scalarField>::New(1, alphaValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getTrackAlphaField
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const wordList& valueSetNames,
|
||||||
|
const List<List<Field<Type>>>& valueSets,
|
||||||
|
const label tracki
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// Fallback value
|
||||||
|
scalar alphaValue(1);
|
||||||
|
|
||||||
|
const entry* eptr = dict.findEntry("alpha", keyType::LITERAL);
|
||||||
|
|
||||||
|
if (!eptr)
|
||||||
|
{
|
||||||
|
// Not specified
|
||||||
|
}
|
||||||
|
else if (!eptr->stream().peek().isString())
|
||||||
|
{
|
||||||
|
// Value specified
|
||||||
|
|
||||||
|
ITstream& is = eptr->stream();
|
||||||
|
is >> alphaValue;
|
||||||
|
dict.checkITstream(is, "alpha");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Enumeration
|
||||||
|
|
||||||
|
const auto option = fieldOptionNames_.get("alpha", dict);
|
||||||
|
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case fieldOption::NONE:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case fieldOption::UNIFORM:
|
||||||
|
{
|
||||||
|
dict.readEntry("alphaValue", alphaValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case fieldOption::FIELD:
|
||||||
|
{
|
||||||
|
const word alphaFieldName = dict.get<word>("alphaField");
|
||||||
|
const bool normalise = dict.get<bool>("normalise");
|
||||||
|
const label fieldi = valueSetNames.find(alphaFieldName);
|
||||||
|
if (fieldi == -1)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Unable to find field " << alphaFieldName
|
||||||
|
<< ". Valid field names are:" << valueSetNames
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Field<Type>& alphaFld = valueSets[fieldi][tracki];
|
||||||
|
|
||||||
|
// Note: selecting the first component!
|
||||||
|
auto tresult = tmp<scalarField>::New(alphaFld.component(0));
|
||||||
|
|
||||||
|
if (normalise)
|
||||||
|
{
|
||||||
|
tresult.ref() /= mag(tresult() + ROOTVSMALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tresult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp<scalarField>::New(1, alphaValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -215,17 +251,47 @@ Foam::vector Foam::gltfSetWriter<Type>::getTrackAnimationColour
|
|||||||
<< abort(FatalError);
|
<< abort(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto option = fieldOptionNames_.get("colour", animationDict_);
|
const dictionary& dict = animationDict_;
|
||||||
|
|
||||||
|
// Fallback value
|
||||||
|
vector colourValue(Zero);
|
||||||
|
|
||||||
|
const entry* eptr = dict.findEntry("colour", keyType::LITERAL);
|
||||||
|
|
||||||
|
if (!eptr || !eptr->isStream())
|
||||||
|
{
|
||||||
|
FatalIOErrorInFunction(dict)
|
||||||
|
<< "Missing 'colour' entry"
|
||||||
|
<< exit(FatalIOError);
|
||||||
|
}
|
||||||
|
else if (!eptr->stream().peek().isString())
|
||||||
|
{
|
||||||
|
// Value specified
|
||||||
|
|
||||||
|
ITstream& is = eptr->stream();
|
||||||
|
is >> colourValue;
|
||||||
|
dict.checkITstream(is, "colour");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Enumeration
|
||||||
|
|
||||||
|
const auto option = fieldOptionNames_.get("colour", dict);
|
||||||
|
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
|
case fieldOption::NONE:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
case fieldOption::UNIFORM:
|
case fieldOption::UNIFORM:
|
||||||
{
|
{
|
||||||
return animationDict_.get<vector>("colourValue");
|
dict.readEntry("colourValue", colourValue);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case fieldOption::FIELD:
|
case fieldOption::FIELD:
|
||||||
{
|
{
|
||||||
const word fieldName = animationDict_.get<word>("colourField");
|
const word fieldName = dict.get<word>("colourField");
|
||||||
const label fieldi = valueSetNames.find(fieldName);
|
const label fieldi = valueSetNames.find(fieldName);
|
||||||
if (fieldi == -1)
|
if (fieldi == -1)
|
||||||
{
|
{
|
||||||
@ -235,52 +301,42 @@ Foam::vector Foam::gltfSetWriter<Type>::getTrackAnimationColour
|
|||||||
<< exit(FatalError);
|
<< exit(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: selecting the first component!
|
const Field<Type>& colourFld = valueSets[fieldi][tracki];
|
||||||
|
|
||||||
scalar minValue;
|
|
||||||
scalar maxValue;
|
scalar refValue(0);
|
||||||
if (!animationDict_.readIfPresent("min", minValue))
|
scalarMinMax valLimits;
|
||||||
|
|
||||||
|
if (pTraits<Type>::nComponents == 1)
|
||||||
{
|
{
|
||||||
minValue = min(valueSets[fieldi][tracki].component(0));
|
MinMax<Type> scanned(minMax(colourFld));
|
||||||
|
|
||||||
|
refValue = scalar(component(colourFld[0], 0));
|
||||||
|
valLimits.min() = scalar(component(scanned.min(), 0));
|
||||||
|
valLimits.max() = scalar(component(scanned.max(), 0));
|
||||||
}
|
}
|
||||||
if (!animationDict_.readIfPresent("max", maxValue))
|
else
|
||||||
{
|
{
|
||||||
maxValue = max(valueSets[fieldi][tracki].component(0));
|
// Use mag() for multiple components
|
||||||
|
refValue = mag(colourFld[0]);
|
||||||
|
valLimits = minMaxMag(colourFld);
|
||||||
}
|
}
|
||||||
const scalar refValue = component(valueSets[fieldi][tracki][0], 0);
|
|
||||||
|
dict.readIfPresent("min", valLimits.min());
|
||||||
|
dict.readIfPresent("max", valLimits.max());
|
||||||
|
|
||||||
const scalar fraction =
|
const scalar fraction =
|
||||||
(refValue - minValue)/(maxValue - minValue + ROOTVSMALL);
|
|
||||||
|
|
||||||
return (colours.value(max(0, min(1, fraction))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vector::zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
Foam::tmp<Foam::vectorField> Foam::gltfSetWriter<Type>::directions
|
|
||||||
(
|
(
|
||||||
const coordSet& points
|
(refValue - valLimits.min())
|
||||||
) const
|
/ (valLimits.max() - valLimits.min() + ROOTVSMALL)
|
||||||
{
|
);
|
||||||
auto tresult = tmp<vectorField>::New(points.size(), Zero);
|
|
||||||
auto& result = tresult.ref();
|
|
||||||
|
|
||||||
if (points.size() > 1)
|
return colours.value(fraction); // 0-1 clipped by value()
|
||||||
{
|
}
|
||||||
for (label i = 1; i < points.size(); ++i)
|
}
|
||||||
{
|
|
||||||
result[i-1] = points[i] - points[i-1];
|
|
||||||
result[i-1].normalise();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.last() = result[points.size()-2];
|
return colourValue;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return tresult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -313,8 +369,7 @@ Foam::gltfSetWriter<Type>::gltfSetWriter(const dictionary& dict)
|
|||||||
// colourMap coolToWarm; // others...
|
// colourMap coolToWarm; // others...
|
||||||
// min 10;
|
// min 10;
|
||||||
// max 100;
|
// max 100;
|
||||||
// alpha field; // uniform|field
|
// alpha 0.5;
|
||||||
// alphaField ageOfAir;
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
@ -363,45 +418,61 @@ void Foam::gltfSetWriter<Type>::write
|
|||||||
{
|
{
|
||||||
const auto& field = *valueSets[fieldi];
|
const auto& field = *valueSets[fieldi];
|
||||||
const word& fieldName = valueSetNames[fieldi];
|
const word& fieldName = valueSetNames[fieldi];
|
||||||
|
|
||||||
const dictionary dict = fieldInfoDict_.subOrEmptyDict(fieldName);
|
const dictionary dict = fieldInfoDict_.subOrEmptyDict(fieldName);
|
||||||
const auto& colours = getColourTable(dict);
|
const auto& colours = getColourTable(dict);
|
||||||
|
|
||||||
const auto talpha =
|
const auto talpha = getAlphaField(dict, valueSetNames, valueSets);
|
||||||
getAlphaField(dict, valueSetNames, valueSets);
|
|
||||||
const scalarField& alpha = talpha();
|
const scalarField& alpha = talpha();
|
||||||
|
|
||||||
const Type maxValue = max(field);
|
const scalarMinMax valLimits = getFieldLimits(fieldName);
|
||||||
const Type minValue = min(field);
|
|
||||||
|
|
||||||
const scalar minValueLimit = getFieldMin(fieldName);
|
// Generated field colours
|
||||||
const scalar maxValueLimit = getFieldMax(fieldName);
|
|
||||||
|
|
||||||
for (direction cmpti=0; cmpti < pTraits<Type>::nComponents; ++cmpti)
|
|
||||||
{
|
|
||||||
vectorField fieldColour(field.size());
|
vectorField fieldColour(field.size());
|
||||||
|
|
||||||
|
scalarMinMax fldLimits;
|
||||||
|
|
||||||
|
if (pTraits<Type>::nComponents == 1)
|
||||||
|
{
|
||||||
|
MinMax<Type> scanned(minMax(field));
|
||||||
|
|
||||||
|
fldLimits.min() = scalar(component(scanned.min(), 0));
|
||||||
|
fldLimits.max() = scalar(component(scanned.max(), 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use mag() for multiple components
|
||||||
|
fldLimits = minMaxMag(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
const scalar minf = max(fldLimits.min(), valLimits.min());
|
||||||
|
const scalar maxf = min(fldLimits.max(), valLimits.max());
|
||||||
|
const scalar deltaf = (maxf - minf + SMALL);
|
||||||
|
|
||||||
forAll(field, i)
|
forAll(field, i)
|
||||||
{
|
{
|
||||||
const Type& v = field[i];
|
const Type& val = field[i];
|
||||||
float f = component(v, cmpti);
|
|
||||||
float minf = max(component(minValue, cmpti), minValueLimit);
|
|
||||||
float maxf = min(component(maxValue, cmpti), maxValueLimit);
|
|
||||||
float deltaf = (maxf - minf + SMALL);
|
|
||||||
|
|
||||||
fieldColour[i] =
|
const scalar f =
|
||||||
colours.value(min(max((f - minf)/deltaf, 0), 1));
|
(
|
||||||
|
pTraits<Type>::nComponents == 1
|
||||||
|
? scalar(component(val, 0))
|
||||||
|
: scalar(mag(val))
|
||||||
|
);
|
||||||
|
|
||||||
|
// 0-1 clipped by value()
|
||||||
|
fieldColour[i] = colours.value((f - minf)/deltaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.addColourToMesh
|
scene.addColourToMesh
|
||||||
(
|
(
|
||||||
fieldColour,
|
fieldColour,
|
||||||
"Colour:" + fieldName + Foam::name(cmpti),
|
"Colour:" + fieldName,
|
||||||
meshi,
|
meshi,
|
||||||
alpha
|
alpha
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
scene.write(os);
|
scene.write(os);
|
||||||
}
|
}
|
||||||
@ -482,6 +553,7 @@ void Foam::gltfSetWriter<Type>::writeStaticTracks
|
|||||||
{
|
{
|
||||||
const auto& field = valueSets[fieldi][tracki];
|
const auto& field = valueSets[fieldi][tracki];
|
||||||
const word& fieldName = valueSetNames[fieldi];
|
const word& fieldName = valueSetNames[fieldi];
|
||||||
|
|
||||||
const dictionary dict =
|
const dictionary dict =
|
||||||
fieldInfoDict_.subOrEmptyDict(fieldName);
|
fieldInfoDict_.subOrEmptyDict(fieldName);
|
||||||
const auto& colours = getColourTable(dict);
|
const auto& colours = getColourTable(dict);
|
||||||
@ -490,46 +562,56 @@ void Foam::gltfSetWriter<Type>::writeStaticTracks
|
|||||||
getTrackAlphaField(dict, valueSetNames, valueSets, tracki);
|
getTrackAlphaField(dict, valueSetNames, valueSets, tracki);
|
||||||
const scalarField& alpha = talpha();
|
const scalarField& alpha = talpha();
|
||||||
|
|
||||||
const Type maxValue = max(field);
|
const scalarMinMax valLimits = getFieldLimits(fieldName);
|
||||||
const Type minValue = min(field);
|
|
||||||
|
|
||||||
const scalar minValueLimit = getFieldMin(fieldName);
|
|
||||||
const scalar maxValueLimit = getFieldMax(fieldName);
|
|
||||||
|
|
||||||
for
|
// Generated field colours
|
||||||
(
|
vectorField fieldColour(field.size());
|
||||||
direction cmpti=0;
|
|
||||||
cmpti < pTraits<Type>::nComponents;
|
scalarMinMax fldLimits;
|
||||||
++cmpti
|
|
||||||
)
|
if (pTraits<Type>::nComponents == 1)
|
||||||
{
|
{
|
||||||
vectorField fieldColour(field.size(), Zero);
|
MinMax<Type> scanned(minMax(field));
|
||||||
|
|
||||||
|
fldLimits.min() = scalar(component(scanned.min(), 0));
|
||||||
|
fldLimits.max() = scalar(component(scanned.max(), 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use mag() for multiple components
|
||||||
|
fldLimits = minMaxMag(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
const scalar minf = max(fldLimits.min(), valLimits.min());
|
||||||
|
const scalar maxf = min(fldLimits.max(), valLimits.max());
|
||||||
|
const scalar deltaf = (maxf - minf + SMALL);
|
||||||
|
|
||||||
forAll(field, i)
|
forAll(field, i)
|
||||||
{
|
{
|
||||||
const Type& v = field[i];
|
const Type& val = field[i];
|
||||||
float f = component(v, cmpti);
|
|
||||||
float minf =
|
|
||||||
max(component(minValue, cmpti), minValueLimit);
|
|
||||||
float maxf =
|
|
||||||
min(component(maxValue, cmpti), maxValueLimit);
|
|
||||||
float deltaf = (maxf - minf + SMALL);
|
|
||||||
|
|
||||||
fieldColour[i] =
|
const scalar f =
|
||||||
colours.value(min(max((f - minf)/deltaf, 0), 1));
|
(
|
||||||
|
pTraits<Type>::nComponents == 1
|
||||||
|
? scalar(component(val, 0))
|
||||||
|
: scalar(mag(val))
|
||||||
|
);
|
||||||
|
|
||||||
|
// 0-1 clipped by value()
|
||||||
|
fieldColour[i] = colours.value((f - minf)/deltaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.addColourToMesh
|
scene.addColourToMesh
|
||||||
(
|
(
|
||||||
fieldColour,
|
fieldColour,
|
||||||
"Colour:" + fieldName + Foam::name(cmpti),
|
"Colour:" + fieldName,
|
||||||
meshi,
|
meshi,
|
||||||
alpha
|
alpha
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
scene.write(os);
|
scene.write(os);
|
||||||
}
|
}
|
||||||
@ -611,7 +693,7 @@ void Foam::gltfSetWriter<Type>::writeAnimateTracks
|
|||||||
scene.addColourToMesh
|
scene.addColourToMesh
|
||||||
(
|
(
|
||||||
vectorField(1, colour),
|
vectorField(1, colour),
|
||||||
"Colour:fixed",
|
"Colour:fixed", // ... or "Colour:constant"
|
||||||
meshi,
|
meshi,
|
||||||
scalarField(1, alpha[0])
|
scalarField(1, alpha[0])
|
||||||
);
|
);
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
\\ / A nd | www.openfoam.com
|
\\ / A nd | www.openfoam.com
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2021 OpenCFD Ltd.
|
Copyright (C) 2021-2022 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -60,9 +60,11 @@ Description
|
|||||||
min 0;
|
min 0;
|
||||||
max 1;
|
max 1;
|
||||||
|
|
||||||
// Alpha channel [optional] (uniform | field)
|
// Alpha channel [optional] (<scalar> | uniform | field)
|
||||||
alpha uniform;
|
alpha 0.5;
|
||||||
alphaValue 0.5;
|
|
||||||
|
//alpha uniform;
|
||||||
|
//alphaValue 0.5;
|
||||||
|
|
||||||
//alpha field;
|
//alpha field;
|
||||||
//alphaField T;
|
//alphaField T;
|
||||||
@ -89,9 +91,11 @@ Description
|
|||||||
// Colour map [optional]
|
// Colour map [optional]
|
||||||
colourMap <colourMap>;
|
colourMap <colourMap>;
|
||||||
|
|
||||||
// Colour [optional] (uniform | field)
|
// Colour [optional] (<vector> | uniform | field)
|
||||||
colour uniform;
|
colour (1 0 0); // RGB in range [0-1]
|
||||||
colourValue (1 0 0); // RGB in range [0-1]
|
|
||||||
|
//colour uniform;
|
||||||
|
//colourValue (1 0 0); // RGB in range [0-1]
|
||||||
|
|
||||||
//colour field;
|
//colour field;
|
||||||
//colourField d;
|
//colourField d;
|
||||||
@ -102,9 +106,11 @@ Description
|
|||||||
min 0;
|
min 0;
|
||||||
max 1;
|
max 1;
|
||||||
|
|
||||||
// Alpha channel [optional] (uniform | field)
|
// Alpha channel [optional] (<scalar> | uniform | field)
|
||||||
alpha uniform;
|
alpha 0.5;
|
||||||
alphaValue 0.5;
|
|
||||||
|
//alpha uniform;
|
||||||
|
//alphaValue 0.5;
|
||||||
|
|
||||||
//alpha field;
|
//alpha field;
|
||||||
//alphaField T;
|
//alphaField T;
|
||||||
@ -131,6 +137,7 @@ SourceFiles
|
|||||||
|
|
||||||
#include "writer.H"
|
#include "writer.H"
|
||||||
#include "colourTable.H"
|
#include "colourTable.H"
|
||||||
|
#include "MinMax.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -151,10 +158,11 @@ public:
|
|||||||
// Enumerations
|
// Enumerations
|
||||||
|
|
||||||
//- Field option used for colours
|
//- Field option used for colours
|
||||||
enum class fieldOption
|
enum class fieldOption : char
|
||||||
{
|
{
|
||||||
|
NONE, //!< Placeholder type (unnamed)
|
||||||
UNIFORM, //!< Uniform value
|
UNIFORM, //!< Uniform value
|
||||||
FIELD //!< field value
|
FIELD //!< Field value
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -187,11 +195,8 @@ private:
|
|||||||
//- Return the colour table corresponding to the colour map
|
//- Return the colour table corresponding to the colour map
|
||||||
const colourTable& getColourTable(const dictionary& dict) const;
|
const colourTable& getColourTable(const dictionary& dict) const;
|
||||||
|
|
||||||
//- Return the field minimum value
|
//- Return the named min/max field limits (from sub-dictionary)
|
||||||
scalar getFieldMin(const word& fieldName) const;
|
scalarMinMax getFieldLimits(const word& fieldName) const;
|
||||||
|
|
||||||
//- Return the field maximum value
|
|
||||||
scalar getFieldMax(const word& fieldName) const;
|
|
||||||
|
|
||||||
//- Return the alpha field for mesh values
|
//- Return the alpha field for mesh values
|
||||||
tmp<scalarField> getAlphaField
|
tmp<scalarField> getAlphaField
|
||||||
@ -219,9 +224,6 @@ private:
|
|||||||
const label tracki
|
const label tracki
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
//- Return track orientation/dirrections
|
|
||||||
tmp<vectorField> directions(const coordSet& points) const;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user