[x3d-public] audio and timesensor synchronization; event-graph routing chains documentation now available

John Carlson yottzumm at gmail.com
Wed Sep 6 15:41:34 PDT 2023


Maybe a bit of impetus to get something working with GraaVM (with node) or
node.js on serverside.

https://stackoverflow.com/questions/50000850/how-to-use-d3js-on-server-side-to-generate-svg-directly

Just use X3D tags instead of SVG tags!

John

On Wed, Sep 6, 2023 at 5:36 PM John Carlson <yottzumm at gmail.com> wrote:

> I had thought of a tables based approach for hierarchies a long time ago,
> but never quite had the bright idea of how to do it.  I'm glad you
> succeeded.
>
> Another way to handle event cycles is to provide a "cycle explorer," with
> separate web pages.  I've done that HTML visualization of cyclic data
> structures in a repository program. Maybe one could do some HTML trickery
> (anchors?) to keep it  all on one page!
>
> We know one can use D3.js with X3D already!  I've not tried X_ITE's DOM
> interface yet.
>
> John
>
> Meanwhile, I'm working on high-level animation in Java, see image
> attached!  Just saw first light!
>
> [image: image.png]
>
> On Wed, Sep 6, 2023 at 3:39 PM Brutzman, Donald (Don) (CIV) <
> brutzman at nps.edu> wrote:
>
>> Glad you like it, thanks John.
>>
>> Yes, I had similarly thought of creating using SVG or D3, which was a
>> high burden of programming stability/interoperability/maintainability over
>> time.  Thus it never got done.
>>
>> Last weekend woke up to realize a tables-based approach was possible
>> using plain old HTML.  Yes tricky to sort out but you only have to get it
>> right once.
>>
>> XSLT is further tricky (unless simple) since declarative, it is a
>> different way of thinking about data structures that is well suited for
>> hierarchal XML trees (like an X3D model). Am currently working on halting
>> (i.e. not infinite looping) if ROUTE loops are present - am thinking that a
>> limit on linking depth no greater that total number of ROUTE statements is
>> sensible.  Interesting problem.
>>
>> For HAnimJoint/HAnimSegment hierarchies, there is already a
>> “visualization report” that Joe Williams and I worked hard to develop.
>> Definitely useful.  There are also styleheets to add (or subtract)
>> representative Shape geometry from a skeleton.  Examples:
>>
>>    - X3D Examples, Humanoid Animation
>>    - https://www.web3d.org/x3d/content/examples/HumanoidAnimation/
>>    -
>>    https://www.web3d.org/x3d/content/examples/HumanoidAnimation/MotionAnimation/Pirouette.html#ROOT_hipHAnimHumanoidReport
>>    - Be sure to scroll down past plain-text tree to colorized report
>>
>> Have fun exploring X3D Examples Documentation!  8)
>>
>> all the best, Don
>>
>> --
>>
>> Don Brutzman  Naval Postgraduate School, Code USW/Br
>> brutzman at nps.edu
>>
>> Watkins 270,  MOVES Institute, Monterey CA 93943-5000 USA
>> +1.831.656.2149
>> X3D graphics, virtual worlds, Navy robotics
>> https://faculty.nps.edu/brutzman
>> ------------------------------
>> *From:* John Carlson <yottzumm at gmail.com>
>> *Sent:* Wednesday, September 6, 2023 8:46 AM
>> *To:* Brutzman, Donald (Don) (CIV) <brutzman at nps.edu>
>> *Cc:* Joe D Williams <joedwil at earthlink.net>; Michalis Kamburelis <
>> michalis.kambi at gmail.com>; x3d-public at web3d.org <x3d-public at web3d.org>
>> *Subject:* Re: [x3d-public] audio and timesensor synchronization;
>> event-graph routing chains documentation now available
>>
>> Wow, Don!
>>
>> Impressive!
>>
>> Can you do something similar for HAnim Joint/Segment hierarchies?  Would
>> an SVG/X3D diagram be better?    Maybe use D3.js and render the HTML to a
>> static page?
>>
>> Again, I am super impressed!  I’m just struggling with reading HTML table
>> into a default table model in Java.
>>
>> John
>>
>> On Wed, Sep 6, 2023 at 8:42 AM Brutzman, Donald (Don) (CIV) <
>> brutzman at nps.edu> wrote:
>>
>>> Appreciate the continuing in-depth analysis, very helpful.  Consistent
>>> authoring and presentation of timing in X3D models is essentially important.
>>>
>>>
>>>
>>> Suggest that we continue to look at useful examples and best practices.
>>> I can keep updating tooltips as appropriate, also various diagnostics.  X3D
>>> Architecture specification is quite detailed.
>>>
>>>
>>>
>>>    - https://www.web3d.org/x3d/tooltips/X3dTooltips.html#TimeSensor
>>>    -
>>>    https://www.web3d.org/specifications/X3Dv4Draft/ISO-IEC19775-1v4-IS.proof/Part01/components/time.html#Concepts
>>>    -
>>>    https://www.web3d.org/specifications/X3Dv4Draft/ISO-IEC19775-1v4-IS.proof/Part01/components/time.html#TimeSensor
>>>
>>>
>>>
>>> To help in this endeavor, am happy to report that we now have improved
>>> support in X3D pretty-print documentation (X3dToXhtml.xslt stylesheet) to
>>> show event-graph routing chains.
>>>
>>>
>>>
>>> Some simple examples:
>>>
>>>
>>>
>>>    - X3D Example Archives: X3D4WA, X3D for Web Authors, Chapter 07
>>>    Event Animation Interpolation, Hello X3D Authors Animation Chain
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter07EventAnimationInterpolation/HelloX3dAuthorsAnimationChainIndex.html
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter07EventAnimationInterpolation/HelloX3dAuthorsAnimationChain.html#EventGraph
>>>
>>>
>>>
>>>    - X3D Example Archives: X3D4WA, X3D for Web Authors, Chapter 07
>>>    Event Animation Interpolation, Color Interpolator Example
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter07EventAnimationInterpolation/ColorInterpolatorExampleIndex.html
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter07EventAnimationInterpolation/ColorInterpolatorExample.html#EventGraph
>>>
>>>
>>>
>>> Complicated example:
>>>
>>>
>>>
>>>    - X3D Example Archives: X3D4WA, X3D for Web Authors, Chapter 07
>>>    Event Animation Interpolation, Time Sensor Chaining
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter07EventAnimationInterpolation/TimeSensorChainingIndex.html
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter07EventAnimationInterpolation/TimeSensorChaining.html#EventGraph
>>>    - The door opens OK but does not again shut satisfactorily, not yet
>>>    sure why…
>>>
>>>
>>>
>>> Some HAnim examples:
>>>
>>>
>>>
>>>    - X3D Example Archives: Humanoid Animation, Winter And Spring,
>>>    Gramps Box Timer Only
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/HumanoidAnimation/WinterAndSpring/GrampsBoxTimerOnlyIndex.html
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/HumanoidAnimation/WinterAndSpring/GrampsBoxTimerOnly.html#EventGraph
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/HumanoidAnimation/WinterAndSpring/GrampsBoxTimerOnlyEventGraphRouteTable.png
>>>    (attached)
>>>
>>>
>>>
>>>    - X3D Example Archives: Humanoid Animation, Motion Animation,
>>>    Pirouette
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/HumanoidAnimation/MotionAnimation/PirouetteIndex.html
>>>    -
>>>    https://www.web3d.org/x3d/content/examples/HumanoidAnimation/MotionAnimation/Pirouette.html#EventGraph
>>>
>>>
>>>
>>> Looking forward to steadily improving adeptness and design patterns.
>>> Have fun with X3D animation!  8)
>>>
>>>
>>>
>>> all the best, Don
>>>
>>> --
>>>
>>> Don Brutzman  Naval Postgraduate School, Code USW/Br
>>> brutzman at nps.edu
>>>
>>> Watkins 270,  MOVES Institute, Monterey CA 93943-5000 USA
>>> +1.831.656.2149
>>>
>>> X3D graphics, virtual worlds, navy robotics
>>> https://faculty.nps.edu/brutzman
>>>
>>>
>>>
>>> -----Original Message-----
>>> From: x3d-public <x3d-public-bounces at web3d.org> On Behalf Of Michalis
>>> Kamburelis
>>> Sent: Tuesday, September 5, 2023 9:42 AM
>>> To: Joe D Williams <joedwil at earthlink.net>
>>> Cc: x3d-public at web3d.org
>>> Subject: Re: [x3d-public] audio and timesensor synchronization
>>>
>>>
>>>
>>> 1. Looking at your attached example code (thanks!) you have a ROUTE from
>>> "TimeSensor.fraction_changed" -> interpolators, but you never start the
>>> TimeSensor. That is, nothing ROUTEs to "TimeSensor.startTime".
>>>
>>>
>>>
>>>     You instead rely that TimeSensor initially runs automatically
>>> because it has loop=TRUE.
>>>
>>>
>>>
>>>     And yes, in this case the TimeSensor will run, but it *does not*
>>> start from zero. That is, the initial "TimeSensor.fraction_changed"
>>>
>>> will not be zero. Instead, the TimeSensor behaves as if it started at
>>> time = 0, which means that it started at "epoch" (1st January 1970).
>>>
>>> Long long time ago, yeah. The initial "TimeSensor.fraction_changed" is
>>> calculated based on this assumption.
>>>
>>>
>>>
>>>     Whatever you do -- any loading, reloading (even loading a completely
>>> unrelated scene in the meantime) keeps this "global time"
>>>
>>> ticking.
>>>
>>>
>>>
>>>     This is indeed a bit weird. I agree with your surprise, I had this
>>> surprise many years ago. It caused me to write this old article on
>>>
>>> https://castle-engine.io/x3d_time_origin_considered_uncomfortable.php
>>> (warning: really old article).
>>>
>>>
>>>
>>>     But the X3D decision was dictated by the desire to support
>>> networking and multi-user worlds. For this, using a "global time"
>>>
>>> (seconds from 1st January 1970) seemed better. And the "startTime" and
>>> "fraction_changed" mechanisms are I guess now too late to change.
>>>
>>>
>>>
>>> 2. The immediate solution (this is also what I heard some years ago when
>>> talking about this) is to make sure you start your TimeSensor(s).
>>>
>>>
>>>
>>>     Simplest way to start something when world loads is to use
>>> ProximitySensor with ridiculous size (so that it for sure includes initial
>>> viewpoint) and ROUTE from ProximitySensor.enterTime to TimeSensor.startTime.
>>>
>>>
>>>
>>>     Like
>>>
>>>
>>>
>>>     """
>>>
>>>     DEF MyTimeSensor TimeSensor { }
>>>
>>>     DEF MyProximitySensor ProximitySensor {
>>>
>>>       size 1000000 1000000 1000000
>>>
>>>     }
>>>
>>>     ROUTE MyProximitySensor.enterTime TO MyTimeSensor.startTime
>>>
>>>     """
>>>
>>>
>>>
>>> 3. From what I know, AD 1 and AD 2 are the way X3D works.
>>>
>>>
>>>
>>>     Comments / tests on other X3D browsers are welcome. If there's a
>>> better advise than AD 2, if the browsers should do something else, I'm all
>>> ears. For now, we follow X3D spec as we have to, from what I know.
>>>
>>>
>>>
>>> 4. To be clear, we really don't do anything like "the tool saves last
>>> TimeSensor fraction before Reopen" as you mention.
>>>
>>>
>>>
>>>     We have no way to do this. The previous nodes are destroyed (when
>>> doing "Open" or "Reopen"), nothing gets saves.
>>>
>>>
>>>
>>>     But the "global time since epoch" keeps ticking, which explains what
>>> you experience.
>>>
>>>
>>>
>>> 5. Fair point that "preserving the camera" during "File -> Reopen" is
>>> problematic if the camera was under the animation. Maybe we should have
>>> separate "File -> Reopen (Reset Camera)" and "File -> Reopen (Preserve
>>> Camera)" in the future.
>>>
>>>
>>>
>>>     For now, just use "File -> Open" then.
>>>
>>>
>>>
>>>     "File -> Reopen" is just a convenience feature, to reload the file
>>> but keep looking at the same thing.
>>>
>>>
>>>
>>> Regards,
>>>
>>> Michalis
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> wt., 5 wrz 2023 o 04:20 Joe D Williams <joedwil at earthlink.net>
>>> napisał(a):
>>>
>>> >
>>>
>>> > - save the current camera (position, direction, up)
>>>
>>> > - save the navigation type
>>>
>>> > - open the file just like opening it using "File -> Open" would do
>>>
>>> > - sets the camera to saved position, direction, up
>>>
>>> > - sets the navigation type to saved type.
>>>
>>> >
>>>
>>> > Hey, maybe that is the way it is supposed to work, but what happens
>>> when you want all that back to the real start at load? if the camera was
>>> animated by being child of an animated thing, it is dropped where it was
>>> when unbound at Open or Reopen. So, if reopen or open, why not put the
>>> camera where the author puts it at open, well first open in his case.
>>>
>>> >
>>>
>>> > > Reopening doesn't do anything special with regards to animations or
>>> time.
>>>
>>> >
>>>
>>> > Well, it certainly doesn't start TimeSensor where the author defined
>>> them to start, that is scene time 0.
>>>
>>> > It remembers old TimeSensor fraction and reopens the animation from
>>> where it was when Reopen happened. So, nothing special, just won't let me
>>> restart from TimeSensor 0.
>>>
>>> >
>>>
>>> > So, for scene time, open and reopen both reset indicated World Time
>>> since load and remembers and sets TimeSensor fraction to when Open or
>>> Reopen stopped TimeSensor by the action.
>>>
>>> > So, looks like the tool saves last TimeSensor fraction before Reopen
>>>
>>> > then I don't know for certain, but TimeSensor starts where it left
>>> off, even after Open.
>>>
>>> > ReOpen, ok, I can see where you might want to save some state as
>>> author convenience, but tool doesn't allow me to actually restart the scene
>>> from initial load state.
>>>
>>> >
>>>
>>> > How can I tell the tool that hey don't remember if this scene,  or
>>> similar, has ever been loaded before, Forget all that partial state from
>>> last time and start from author-defined initial state as written in the
>>> user code.
>>>
>>> >
>>>
>>> > This pain really shows when authoring a scene with animations that
>>> want to be in sync with an audioclip.
>>>
>>> > Can't work on the thing because a Open or Reopen only affects the
>>> audio startTime and the TimeSensor startTime carries on from where it left
>>> off last.
>>>
>>> >
>>>
>>> >  > I don't know exactly how you run your animation,
>>>
>>> >
>>>
>>> > From a TimeSensor fraction_changed into Interpolator(s).
>>>
>>> > From what I showed, when the audio begins,I send audio StartTime to
>>> TmeSensor startTime and isActive to enabled. it begins to play audio and
>>> animation.
>>>
>>> > The animation cycle time is slightly less than the audio time time so
>>> I want the animation to complete and not repeat, then the audio to end and
>>> not repeat.
>>>
>>> > All that basically works ok, unless the tool happens to recall where
>>> this or a similar file has been Opened by it. If not first Open, or if
>>> Reopen, the audio starts fine, but the TimeSensor is off in memorylands,
>>> having started from where it was last running.
>>>
>>> >
>>>
>>> > Try  and see, even some simple TimeSensor example like attached. After
>>> the first Open, I bet you can't get it to start from 0 again.
>>>
>>> >
>>>
>>> > > Time origin" of X3D spec. It may make some things weird,
>>>
>>> >
>>>
>>> > Yes, SFTIme can be absolute or relative or an interval
>>>
>>> >
>>>
>>> > Anyway,is it a bug, or how it is supposed to work? I say for the Open,
>>> it ought to be purely what the author gives as initial state. For Reopen,
>>> if the tool wants to retain some state, then ok, but for time,  I have a
>>> question if for Open#1 World Time since load is very close if not the same
>>> as Scene Time.
>>>
>>> > But  for open#2 or Reopen, World Time since load gets reset to 0 but
>>> Scene Time is most likely very different., in fact, the same as left off by
>>> Reopen.
>>>
>>> >
>>>
>>> > Thanks for thinking about this. Simple example attached. Open it,let
>>> it run for a while, then Reopen or Open. It opens with a viewpoint child of
>>> the thing that is moving so the viewpoint movement shows as the model moves.
>>>
>>> >
>>>
>>> > When it starts to run, the Scene Time at Reopen will be Scene Time
>>> when you initiated the Reopen or Open. The camera assignment provided by
>>> the author for initial viewpoint is ignored and this viewpoint is left
>>> floating, suddenly parentless, apparently. Page Down recaptures the
>>> viewpoint so you can see the camera location change.
>>>
>>> >
>>>
>>> > Thanks,
>>>
>>> > Joe
>>>
>>> >
>>>
>>> >
>>>
>>> > f behin
>>>
>>> >
>>>
>>> >
>>>
>>> > Original Message-----
>>>
>>> > From: Michalis Kamburelis <michalis.kambi at gmail.com>
>>>
>>> > Sent: Sep 4, 2023 2:56 PM
>>>
>>> > To: Joe D Williams <joedwil at earthlink.net>
>>>
>>> > Cc: <x3d-public at web3d.org>
>>>
>>> > Subject: Re: [x3d-public] audio and timesensor synchronization
>>>
>>> >
>>>
>>> > I understand that by "Reopen" you refer to view3dscene "File ->
>>>
>>> > Reopen"? To be clear, all it does is
>>>
>>> >
>>>
>>> > - save the current camera (position, direction, up)
>>>
>>> > - save the navigation type
>>>
>>> > - open the file just like opening it using "File -> Open" would do
>>>
>>> > - sets the camera to saved position, direction, up
>>>
>>> > - sets the navigation type to saved type.
>>>
>>> >
>>>
>>> > Reopening doesn't do anything special with regards to animations or
>>> time.
>>>
>>> >
>>>
>>> > If you believe it does have a bug, please submit a simple testcase to
>>>
>>> > show the problem -- a complete X3D file that I can load in view3dscene
>>>
>>> > and see the problem will be appreciated.
>>>
>>> >
>>>
>>> > Note that VRML and X3D internally use absolute time (seconds since
>>>
>>> > January 1, 1970) in SFTime. See "8.2.2 Time origin" of X3D spec. It
>>>
>>> > may make some things weird, but following the spec -- for good or bad.
>>>
>>> > But I speculate, I don't know exactly how you run your animation, I
>>>
>>> > need more information than above.
>>>
>>> >
>>>
>>> > A proper usage is certainly possible, such that each opening of the
>>>
>>> > file runs the animation correctly from start. If you ROUTE to
>>>
>>> > TimeSensor.startTime values e.g. from ProximitySensor.enterTime or
>>>
>>> > TouchSensor.touchTime, it will behave as expected.
>>>
>>> >
>>>
>>> > Regards,
>>>
>>> > Michalis
>>>
>>> >
>>>
>>> > pon., 4 wrz 2023 o 22:01 Joe D Williams napisał(a):
>>>
>>> > >
>>>
>>> > > Hi All,
>>>
>>> > > I have a scene with AudioClip and TimeSensor animations.When Open,
>>> if same file then, same as Reopen, the audio restarts, but the animation
>>> time sensor (after instantaneous reset to 0) restarts where it left off,
>>> rather than actually restarting. This leaves the sound and animations out
>>> of synch and so useless. Really appears like my timer is running with
>>> WorldTime when it is turned off then gets reset using relative to World
>>> Time when reopen or open.
>>>
>>> > >
>>>
>>> > > I thought I should have the answer to this by starting the animation
>>> timers under control of the audio startTime. Just don't start animation
>>> timers until audio starts then all should synch.
>>>
>>> > >
>>>
>>> > > So, I can understand some caretaking like this when the author is
>>> reloading to fix some stuff and just wants to proceed rather than start an
>>> animation over from the beginning, but it seems to me that the author also
>>> ought to have the keys to get a complete restart from the beginning.
>>>
>>> > >
>>>
>>> > > So, in this case, I really do want to be able to keep this audio in
>>> sync with the animation. When I do tell the animation timer to start with
>>> the audio, I want to be able to depend on that rather than the tool taking
>>> over and deciding what to do with regard to the TimeSensor timing depending
>>> upon the last time I did Open or Reopen with the same or similar file. In
>>> this case the Audio startTime sent to the animation timer is not being
>>> honored.
>>>
>>> > >
>>>
>>> > > This is how it is coded:
>>>
>>> > >
>>>
>>> > > enabled='false' loop='true'/>
>>>
>>> > >
>>>
>>> > >
>>>
>>> > > loop='true' enabled='true'
>>>
>>> > > url='"wrv2_103seconds.wav"'/>
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > > toField='set_startTime' toNode='GBTimer'/> toField='set_enabled'
>>>
>>> > > toNode='GrampsBoxTimer'/>
>>>
>>> > >
>>>
>>> > > Is the basics. When the audio starts, then the animation timer
>>> starts. But I also want to stop the animation at the last frame when it
>>> ends, instead of repeating the animation. There must be a better way, but I
>>> am using:
>>>
>>> > >
>>>
>>> > > key='0 0.9 1' keyValue='true false false'/> toField='set_fraction'
>>>
>>> > > toNode='GBTimerLoopControl'/> toField='loop' toNode='GBTimer'/>
>>>
>>> > >
>>>
>>> > > Which turns off the animation timer after one cycle.
>>>
>>> > >
>>>
>>> > > Sending the loop false twice seems necessary since if sent only at
>>> fraction time 1 it lets animation timer move to start and actually send 0
>>> fraction instead of ending at last frame. I think the loop true/false
>>> should be evaluated before start is set, not set start then check loop,
>>> Loop false at tic fraction 1 should not allow the timer to proceed to 0. If
>>> loop is false at load,then start is not sent.
>>>
>>> > >
>>>
>>> > > And I also want the AudioClip to stop after one play with no repeat
>>> so I did this:
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > > Since the animation timer ends its cycle a few seconds before the
>>> audioclip, (100 seconds vs 103 seconds) this should also keep the audioclip
>>> from looping. Unfortunately,it does not and the audio continues until it is
>>> stopped by unknown, Seems like loop false recognized some time later than
>>> needed to stop the audio at its end. as the audio plays. By changing the
>>> animation timer cycletime I see the loop false is recognized at some time
>>> which seems related to when I send the audio loop false and that I might be
>>> able to with luck pick a lucky time that matches the stop time I need.
>>>
>>> > >
>>>
>>> > > So, please help me figure out how to control this thing the way I
>>> need to.
>>>
>>> > >
>>>
>>> > > Thanks All,
>>>
>>> > > Joe
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > > .
>>>
>>> > >
>>>
>>> > >
>>>
>>> > >
>>>
>>> > > _______________________________________________
>>>
>>> > > x3d-public mailing list
>>>
>>> > > x3d-public at web3d.org
>>>
>>> > > http://web3d.org/mailman/listinfo/x3d-public_web3d.org
>>>
>>> >
>>>
>>> >
>>>
>>>
>>>
>>> _______________________________________________
>>>
>>> x3d-public mailing list
>>>
>>> x3d-public at web3d.org
>>>
>>> http://web3d.org/mailman/listinfo/x3d-public_web3d.org
>>> _______________________________________________
>>> x3d-public mailing list
>>> x3d-public at web3d.org
>>> http://web3d.org/mailman/listinfo/x3d-public_web3d.org
>>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20230906/e8cc578c/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image.png
Type: image/png
Size: 135765 bytes
Desc: not available
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20230906/e8cc578c/attachment-0001.png>


More information about the x3d-public mailing list