# Virtual Scattering Application

Page 6 of 8   1, 2, 3, 4, 5, 6, 7, 8

## Re: Virtual Scattering Application

Strictly speaking, the create*Spiral* functions should actually be create*Helix* functions. I just checked the definitions to determine the difference and a spiral should have an increasing or decreasing radius, but a helix has a constant radius. So we really have helices already.

Maybe I should create a new set of create*Helix functions, which will just be the current implementations, and then fix the create*Spiral functions to actually create a spiral. I will probably rename radius to be startRadius and add an endRadius property to control the changes.

The inside-out object is caused, I think, by mis-using the THREE.BoxGeometry class. It isn't meant to create curved shapes. I think the way you are manipulating the vertices of that geometry is causing the inside-out-ness. You are using a cosine function which will return negative numbers for some input values. I think that is causing the geometries vertices to be re-arranged.

There are a number of ways to turn a geometry inside-out. Firstly, you can specify which face to render in the Material. You can render only the Front Face, the Back Face, or you can render both faces. But that is not your problem.

Secondly, you can set the normals in the geometry to point in a certain direction, and that direction will be determined to be the Front Face. But that is not your problem.

Thirdly, in lieu of specified normals, it will try to guess the normal. It does that by assuming that the vertices are specified in anti-clockwise order (sometimes it is clockwise, but I think THREE uses anti-clockwise). All polygon geometry is broken down into triangles in order to be rendered. The order of the 3 vertices that make each triangle can be used to determine the face direction, or normal. I think this is your problem.

Because you are manipulating those vertices, I think it is changing the apparent order of them. You might have started with a triangle with vertices at (0,0) - (1,1) - (0,1). We'll use 2D for simplicity. Now if we inverted the Y values, we would have (0,0) - (1,-1) - (0,-1), which are now in clockwise order instead of anti-clockwise. That will flip the face normal over and it will render from the opposite direction.

You should be able to use the create*Spiral functions to do what you are. Reduce the tubeSegments and/or radialSegments until you get the effect you want. The tubes can be square.

I also fixed another problem that you didn't mention. There was an invisible spiral going through the center of the arrangement. It was using the wrong kind of Material so it didn't render.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

.

Here a rudimentary concept design for rotating each of the six spheres into the central - perhaps elevated - 'Burner' position. The central position and switchout mechanisms can be as imaginative as you like. I may slow things down a bit. Alternative 2 might be where the six spheres would be rotated through a burner which is fixed at 3, or 12 o’clock.

After an hour or two of effort I was sure to mention being unable to get a working mesh for 'spiralHelix' to work. I'm glad you found it. I tried to put it to good use in the image above.

Great read on boxHelix’s inverted surfaces. I went directly to the Ribbon function – and observed that a negative sign added to either v.x or v.z corrected the helix’s surface appearance. I went to the source and was grateful to notice that I had not inadvertently dropped the negative sign and created the inverted appearance myself.

Code:
`(function( generator ) {      ribbonAFct = function( v ) {           let angle = -v.x;           let radius = Math.sin(this.angleR)* ringConfigRadius * mult2  - v.z;              let shift = (v.x / (Math.PI * 2)) * generator.rbnStepLength + v.y;           // a neg sign is required either v.z or v.x to view the outside surfaces correctly.           v.x = Math.cos(angle) * radius;   // v.x = -1*Math.cos(angle) * radius;             // v.y = shift; // lets y remain constant            v.z = -Math.sin(angle) * radius;       }}( this ));`

I also tried commenting out v.y. This had the result of making the box Helix into a well defined circular ring with very nice ends! I believe BoxHelix can be used to make the tubes or pipes I was hoping for. The image included shows a 300 degree boxHelix around the outside perimeter of spheres. I imagine a rotating central inner wall with a 60 degree opening that would allow only one sphere access to the central location.

I tried reducing spiralHelix’s tube segments to four, thereby creating a spiraling square cross section. That doesn’t compare well with boxHelix’s definite specifiable rectangular cross section. The four sided - square tube - is most visible on the start and end sections. Please let’s keep both the Box and Spiral Helix functions - the two are very different.
.

Last edited by LongtimeAirman on Sat Jul 06, 2019 10:34 pm; edited 1 time in total (Reason for editing : Corrected the http: code typo)

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

.

Another alternative 1 possibility.

All the guns shown are animated in two ways, with color changes, and a 180deg alternate rotation. I'm playing with the available parts - treating it as a construction set, trying to come up with something appealing. The image included shows a better example of a ‘cycling through the center burner position’ mechanism.

The central spiralHelix (and supporting structures such as barrel – etc - remains oriented toward the target. The boxHelix rings must rotate as necessary to place any of the six spheres into the forward firing position.

Or how about a Jitterbug structure. A shape that would open as it were spun, but which closes when the spin stops. That may be a bit difficult. Forgive me if I'm over-complicating a simple exercise in applying animations.
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

.

How about this?  An r=1.5 sphere in the center is connected by springs (or rods or some mechanism) to six r=1 spheres in the Cardinal positions (+/-X, +/-Y, +/-Z). There is a framework of three orthogonal raceways which rotate or bump and roll all 4 of the 6 outside spheres 90 degrees on the inside of one of the three orthogonal racetracks at a given time. For example, the center sphere retracts the spring connections from the 4 (+/-X, +/-Z) outside spheres. Next, the +/-Y axis rotates the +/- Y race track + or – 90 degrees about the Y-axis like a carousal. For any given position and allowing a single +/- 90 degree rotation, there are 6 possible rotations.

Once again, there’s an existing alternating rotation animation that rotates all the Revolver gun components 180deg back and forth about the target/gun y-axis. I’d like to add 6 new 90 degree rotations plus some mechanism action. All the curent components will rotate 90 degrees about the gun’s X, Y, or Z axis. I'd like to be able to cycle all the r=1 spheres through the forward emission position.

Side note. The field distortion is surprising, it forces me to re-verify all the component sizes and positions.

Feel free to suggest changes, there are plenty of meshes in the code to play with. Your coordination, input, and approval are respectfully requested.
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

I like the springs. They could use a little bit more resolution though. They look fine in the images above, but when I loaded it up they looked a bit flat. Increase the tubeSegments or radialSegments value. I think it is the latter. They could also use a smaller radius as they are getting covered a bit too much in the current incarnation. Maybe give them more compression too, as in the spring in compressed. More spiral angle per length.

Maybe try some other textures rather than the honeycomb. I do like that honeycomb, but there may be some others that work just as well.

I think the field distortion is caused by the camera settings.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

.

This image is taken from a position very close to the previous in order to be able to closely compare the two and see that the recommended changes were made. The springs are definitely nicer. I verified and corrected a couple of framework spacing errors which are too difficult to see here. The spheres shown are ‘rock’ textured. The only place that honeycomb appears is at https://img.nevyns-lab.com/textures/ and thats where I found the rock.
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

.

I’m thinking I could use arcs to simplify the Revolving gun framework and as a possible rotation mechanism. Neither the spiral nor bow Helices can produce a ninety degree arc. Is it too late to beg for Torus Buffer geometry? Other than that I’m satisfied with the present configuration of the Revolving gun. The rock spheres still pulse with a color animation and I also like the concrete color for the framework and center sphere 'structure'. The springs are still under some consideration – I made a random color generator but that varies too much; in the image above, the springs are MeshLambertMaterial({color:'orange'}). The springs make a nice measuring device, showing the camera field distorts all objects equally.

Revolving gun still has the alternating-rotation animation, turning 180 degrees in the Y-positive direction followed by a 180 degree turn toward the Y-negative direction. Sorry, I imagine you’re bored to tears with my progress, animations are still beyond my grasp. I went back and reviewed your explanations and directions. I also did a search on “javascript animations” and came up with a few hits I need to review. Simplifying my immediate plans I’d like to make two other alternating-rotations - about the X and Z axii. We know there can only be one alternating-rotation animation operating at a time, so the three animations would need to be alternated somehow. I don’t know if that’s a delegate function or not.
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

It looks great. I really like the rings around the center sphere. They mesh together nicely. The roll-cage looks good too.

Maybe try using a MeshPhongMaterial on the springs. It is more expensive but looks a lot nicer. If it doesn't look a lot better, then go back to Lambert.

Find some nice colors that work well together. Simple can sometimes be better here. Fading from black or white into another color can work really well. Same for a natural color (for whatever texture is being used) into a bright or dull color can look good. It really depends on what you want out of it.

What sort of geometry do you need? We previously discussed a pipe with an inner and outer wall of different radii. Are you thinking of something different now? Looking at your images above I could see some geometry that spans the parallel bars in the roll-cage. You would specify the inner and outer radius, and the width of the ring.

I did make some progress on that pipe geometry, but haven't worked on it recently. I haven't done any programming recently, but haven't forgotten about it.

Airman wrote:We know there can only be one alternating-rotation animation operating at a time, so the three animations would need to be alternated somehow. I don’t know if that’s a delegate function or not.

Not quite correct. In the case of the alternating rotations, which use the WaveAnimator class, we can have as many delegates as we want, and each delegate will rotate a different part. They could rotate the same parts, but that would be better handled by a single rotation which is a combination of the two, but sometimes it just works better to have two separate rotations for other reasons.

The WaveAnimator class should be thought of as the timing mechanism. It is the clock. The delegates are the actions that occur based on the current value of the wave. If we have 3 rotations that we want to apply, and they are all based on the same timing, then we can use a single WaveAnimator for all of them. However, if 1 of them needs to be based on a different timing scheme, then it will need its own WaveAnimator that has different settings than the other.

Any WaveAnimator can have as many delegates as you want to add to it. It is preferable to have more delegates than WaveAnimators, but not necessary, and only when it makes sense to do so.

Here's how I would go about such things. When I add new functionality to a section of existing code, I create it without regard to the rest of the code (except for how it fits into it). What I mean is, I would create a new WaveAnimator object for the new section and not re-use an existing one. Once I have it working the way I want it to, then I go and look for other WaveAnimator objects that might be able to do the same job, and use it if I find one. This allows total freedom to change that WaveAnimator (or whatever it is) without effecting other code while I work on it.

Basically, don't worry about efficiency, just get it working the way you want it to and we can find alternative ways later.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

.

What sort of geometry do you need?
I was delirious, begging for Torus Buffer Geometry, forgetting that I had used torus rings in the Helix Ring gun.

This was an important change that I was anxious to make since I believe it provides a more believable, viable mechanism. The torus function allowed me to change each boxHelix ring into four separate arcs, changing the outside framework from a single roll cage made from six rings – 3 parallel pairs orthogonal to each other – into 8 independent octants. Each octant is a spherical triangle made of 3, roughly 80 degree arcs. Each framework convex octant is matched by a sort of concave octant wrapped around the central sphere between the springs; I believe I might be able to coordinate those structures without interfering with the 6 desired 90 degree rotations of the springs and spheres.

The previous cardinal points had a square opening which each sphere fit into, now each sphere is held by four points which – in my imagination - no longer prevent spheres from following the frameworks’ three orthogonal tracks. The core sphere and spring assembly can now rotate the outside spheres in any of the three plus/minus directions without needing to pull any spheres in toward the central sphere. The only downside is that all 48 arc ends are uncapped. It seems too expensive to correct – my sensibilities might allow it.
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

.

In this image, the Revolving gun’s octant cage has an alternating y-rotation animation of PI radians about the stationary 'spheres and springs' central assembly.

I’ll admit, this latest task proved difficult and the result is not what I’d imagined. My sensibilities don’t allow me to rotate the forward sphere while the gun is firing; so, while the gun is firing, the spheres may only be allowed rotations about the y-axis. On the other hand, the framework cage is free to rotate about any axis. The question – why would they? – will also burden my sensibilities. I'll need to find another mechanical component like a gear or linkage. I think I'll be able to add some action. Is there any particular idea you had in mind?

My next logical question/step - How can we sequence or randomize these rotations so that I can have more than just the one rotation? I’ll try adding all the rotations then finally look more closely at the delegate function.

Possible future alternative - can we tie the Revolving gun's animations to the start and stop firing buttons; such that when the stop firing button is pressed the gun stops firing and is immediately rotated out of the forward position? Can we add a set of new +/-X, +/-Y, or +/-Z buttons for a firing interruption to allow the spheres to rotate about x or z?
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

.

This image shows a couple of changes. The first is too difficult to discern here – the rollcage framework and spheres/springs central assembly are both counter-rotating about the y-axis, two instances of using the alternatingRotation animation. Or, my senses be damned, I can let the cage roll about any direction; it’s confusing, but not half bad.

The second change is also a pleasant surprise, please note that each Revolving gun is a different color. It happened when I inserted line 856 in the createModel function.
Code:
`animator.phase = Math.random() * 2 * Math.PI;  // Each Revolving gun now has its own unique color.`

Slowly I learn. I mentioned failing to get different phase colors for each sphere within each Revolving gun. I only tried adding the animator to the coreAssy group. It occurs to me now that I’m going to have to add the animator and random phase alongside each sphere’s mesh as it is added to the coreAssy.

This image also includes uncapped arc ends near 9 oclock at the target boundary.

Thanks again for the playground. I haven't gotten to sequencing anything yet. The waveAnimations are cyclical, never-ending, and so they cannot be sequenced. I guess I need to figure out how to make a simpler animation out of a single 90 degree turn.
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

Sequencing is a bit trickier, but I have some code in place for it. I haven't actually implemented anything with it yet, and it probably needs more work, but I think the premise is workable.

The Model class, which GunModel extends, has a property called data that is not used by the Model class, but is there for Animator and Action implementations to use for their own purposes.

The initial idea was that Actions would change the value of a data property which Animator(s) are watching. However, Animators can change those data properties too, so there is no need for Actions if they don't fit your needs. Actions are not very well defined at the moment. The Gun class currently has only 2 defined Actions: FIRE and RELOAD. They were defined before I got too far into the app and I'm not sure if they are appropriate anymore. In the very least, I would like to add START_AUTO_FIRE and STOP_AUTO_FIRE.

So you could have an Animator that uses a data property to determine which dimension to rotate about, maybe. Each time it rotates about 1 dimension, it switches to another so the next rotation will be about that dimension. You may need to be careful about when you switch the data property, since you want to wait until the full rotation has occurred. It should be based on the current wave value (usually when it is 1 which is the full rotation).

I don't have time to go any further into it, but see if you can work with that mechanism and ask any questions you come up with.

Note that the current color phasing will not work directly with this method, but can be wrapped in another function that does. I'll look into it when I get the chance. That might go a bit quicker if you can describe exactly what you want, in numbered steps. Then I will be able to find a way to make it happen within the framework.

Nevyn

Posts : 1744
Join date : 2014-09-11

## How to use Data Properties

The Model class, or a sub-class of it, is used to contain the data for a given instance of whatever is being created. A gun in this case. It has ways to associate Animators and Actions, and provides the mechanism to execute them. The Model is the center of it all. Both Animators and Actions are given the Model when they are executed, which allows them to be Model agnostic, so they can be used on any number of Models at the same time (assuming the Animator or Action implementation does not cause problems with that).

The next step is to create a way for Animators and Actions to communicate. This is where data properties come into it. Since the Model is common to all, it is used to store the data properties so that they are available to all Animators and Actions executed on it, and also so that they are unique to each Model in the case that a single Animator or Action is used on multiple Models.

We have seen the materials and parts properties on the Model class already, and data properties are not much different. In fact, the only difference is that the Model class will never use anything in there, and they may contain any data that you want, not just Material or Object3D objects like materials and parts.

Here is the definitions of these properties in the Model constructor:

Code:
`module.Model = function(){ this.object3D = new THREE.Group(); this.direction = new THREE.Vector3( 0, 1, 0 ); this.parts = {}; this.materials = {}; this.actions = {}; this.animators = {}; /** * This object can be used to store any data you want * associated with a Model. It is totally user controlled * and not used by this class. It is meant to be used as * a communication system between Actions and Animators, * allowing you to setup actions that control animations. */ this.data = {};};`

You can see that it is just an object, like any other. It can contain any properties that you want. You just set a value like this:

Code:
`var model = ...model.data.myDataProperty = 'some value';model.data.myDataPropertyArray = [ 2, 4, 6, 8, 10 ];model.data.myComplexDataProperty = {  type: 'integer',  value: 456};`

The names of the data properties are whatever you want, but you must take possible collisions into consideration. That is, you must make sure that the properties are unique. Let's say you use 2 Animators on a given Model, and each of them wants a data property for some purpose. If you use the same name for each Animators data property, then they will collide and use the same value. This may be exactly what you want, but if it is not, then you must use unique data property names to avoid collision. It may even be preferable to use an object to store all properties for each Animator. Like this:

Code:
`var model = ...model.data.animator1 = { start: new THREE.Color( 0, 1, 0 ), end: new THREE.Color( 0, 0, 1 ) };model.data.animator2 = { start: new THREE.Color( 1, 1, 0 ), end: new THREE.Color( 0, 1, 1 ) };`

## Data Properties for Animators

Now that we can declare some data properties, we need to actually use them. The Animator is given the Model when it is executed, so it just needs to reference the data properties and use them in an appropriate way.

Suppose we have a WaveAnimator and we want to use it to rotate a single part, but in 2 different dimensions. We will set it up such that when the wave is ascending it will rotate one dimension, and when it is descending it will rotate the other.

Firstly, we create the Model and WaveAnimator like this:

Code:
`var model = new Scattering.GunModel();model.data.dimension = 'x';model.data.angle = Math.PI/12;var animator = new G3D.WaveAnimator( ... );`

Now we need to create a delegate that will rotate the part, which we will assume has been added to the Model and is called 'myPart':

Code:
`var animator = new G3D.WaveAnimator( ... );animator.add( function( time, model, value ) {  // apply the rotation  var part = model.parts.myPart;  part.rotation[model.data.dimension] += model.data.angle;  // see if we need to switch the dimension  if( value === 1 )  {    model.data.dimension = 'y';  }  else if( value === 0 )  {    model.data.dimension = 'x';  }} );`

Now, that may not work very well because we can't guarantee that value will actually reach 1 and 0. It really needs to record the last value and then subtract the current value from that and determine if it is positive or negative, but I don't want to add too much complexity.

### Data Properties for Actions

Actions are not that different from Animators in this regard, but it is worth pointing out their differences anyway. An Animator is always being executed. Every frame. An Action, on the other hand, is only executed when something happens. The Model class stores the Actions, but it does not execute them of its own accord. It may be easier to use an example for this.

We have been using the GunModel class as our Model, and this is used to represent the 3D nature of the Gun class. The Gun class provides methods that do something with that Gun, say, fire a bullet. When the Gun.fire method is invoked, it will execute any Actions stored in its Model under the Gun.Action.FIRE name (which is 'fire' as a value). So we can store Actions on a GunModel that do something every time the Gun is fired.

Code:
`var model = new Scattering.GunModel();model.addAction( Scattering.Gun.Action.FIRE, function( model ) {  model.data.fired = true;} );`

That is a bit of a contrived example, and doesn't do anything useful, but it shows how to define the Action and alter a data property. We could have an Animator that is watching the fired data property and only executes when it is true.

I have some Action implementations for various purposes in the g3d-actions.js file. Check them out in the G3D API documentation. I'm not sure how useful they will be. I just implemented them trying to get a feel for how Actions will work.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

.

… see if you can work with that mechanism and ask any questions you come up with.
I’m not sure exactly what you mean by ‘mechanism’, so I’ve included an autocad image of my track switching mechanism.

Again, please forgive the repetition. The springs and central sphere are omitted for clarity. Only the ‘details’ for the central octant with corners xPos, yPos and zPos are included. The current Revolving gun's configuration of y axis, contra rotating, spheres(and springs) and framework roll cage as shown on the left. The roll cage is formed by eight spherical triangle 'octants' leaving three, X,Y,Z open framework raceways between them. The six spheres occupying the cardinal position spheres are ‘free’ to rotate – as a unit - about any one of those three axii.

At right, I try to show a possible track ‘switching mechanism’. The central octant is shown in its yPositive switch position. At its YPos apex angle, both of the 80degree arcs have extended halfway across the X and Z raceways in order to restrict the sphere in the YPos position. The remaining two +/- X and Z octant angles each extend only one of the two arc ends, only allowing free rotation about the y axis. During ‘operation’, for a y spin axis rotation, all the octants are switched to their respective y axis positions. This may include another possible mechanism, the switch selection performed by the center assembly.

I wish to introduce sphere/spring and roll cage rotation direction changes. I believe the main strength of this idea is its simplicity, I’ve already been messing with these arcs, small extensions (fixed angle rotations actually ) should be ‘easy’. I don’t need to worry about the greater complexities of retracting or extending the springs and spheres.

Again, I greatly appreciate the opportunity, but I believe you are the client. You need to be satisfied, your approval is necessary. Always feel free to suggest changes.

.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

The problem with this type of operation is that the firing rate is far too high. There is not enough time between bullets to do anything. We can still make it work, but from another angle, figuratively speaking.

Instead of tying it to the firing, you could just make it a charge-discharge cycle. The sphere rotates into place at the front. It then begins a color phase as if it is dis-charging. When it is empty (maybe a black color), then it moves out of position and the next sphere moves in. We don't want all 6 directions, only 4 of them, since the other dimension is difficult to work with. So the spheres are just rotating in a circle.

We should be able to setup some color phasing that is not continuous. We want the spheres to move from a bright color to a dark color when they are in the front position, signifying dis-charge. In the other positions they could be re-charging, or you might only recharge them in the back position, leaving a completely dis-charged sphere to the left (say) and a fully charge sphere to the right.

You could even have some sort of nozzle that appears to take the charge from the spheres. This would never completely dis-charge but appear to be refilled by the sphere that is in the front position. Otherwise it might look a bit strange that the gun is firing when there is no sphere in the front position.

This is starting to get complicated, and the current framework may not be enough to get this working, or it might be less efficient than it could be. Once we have a clear idea of what we want to happen, then I can find a better way to implement it. I'm starting to get an idea for chained animators. A series of animations that occur one after the other. A lot of programming is throwing around ideas until you find something that you like.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

Here's another idea, both the front and back spheres dis-charge together and the side spheres re-charge together. The helices connecting them also color phase to match it.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

.
Good, we can have additional actions and rotations, or rather ‘data driven action animations’. We may develop additional actions – eventually – on game state changes, not yet fully defined.

Agreed, the switching mechanism I’m playing with is much slower for the firing rate. Logically, the spheres are a power source and should not be the emission source; no problem, a charge/discharge cycle it is. Emissions won’t come from spheres.

Well I’ll have you know I had an alternative ready. In my possible track switching mechanism image above, imagine the emissions coming from the center of the configuration instead of the y+ sphere. All the sphere/spring and roll cage rotations do not interfere with the gun firing.  But no, your comment,
We don't want all 6 directions, only 4 of them, since the other dimension is difficult to work with. So the spheres are just rotating in a circle.
devastates that idea. What? Circles only? Are you sure? I could easily beg, how about a compromise configuration?

Please consider a cube configuration – with 8 spheres occupying the corner positions. Four forward spheres, a face, is presented toward the target. The emissions will emerge from the center of the configuration. The 8 spheres can rotate along two each x y and z spins equivalent to a 2x2x2 Rubiks cube. Can we actually mix up the spheres that way?
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

I only limited it to a circle for that scenario for simplicity. If you want something else then that's fine too.

One thing to think about is size. We can't have the guns being so large that they cover what we want to see.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

.

Status. I began a new ‘Cube gun’ by copying Revolving gun.

The 8 spheres are arranged about a center spring – a temporary stand in for a ‘central structure’.  The end of the central spring opposite the target is the gun’s center point (0,0,0). I’m in the ‘middle’ of trying to align the 8 surrounding springs from the spheres toward (0,0,0).

Question, why does the barrel place itself in front of the forward-most component?
I cannot place any component further forward than the barrel. In other words, I cannot place the barrel inside the configuration. – with respect to the y axis. As a constraint, all well and good, after I properly align the outside springs, the barrel will be closer to the configuration’s center, and I may connect that spring directly to the barrel.

Aligning the springs has been difficult. I’ve tried simple geometry, and quaternions – you’ll no doubt recall the following code. It doesn’t seem to work. I’m surprised the line
Code:
`mesh.orientation = quat;`
doesn’t give me an error. I'm not asking for a review (yet). Do you see any major malfunctions in my thinking? How should one change the orientation of the spring meshes?

Code:
`// create a vector to represent the line from p1 to the point on the object that needs to be oriented towards p2.  var p1 = new THREE.Vector3( 0, -1, 0 ); // calculate the vector between the location of the object and the target point //var p2 = new THREE.Vector3( - 1.0 * points[i].x, - 1.0 * points[i].y, - 1.0 * points[i].z ); var p2 = new THREE.Vector3( -i, -j, -k ); // this is where align will end up at the end of this algorithm var v = new THREE.Vector3().subVectors( p1, p2 );  // calculate the angle between those 2 vectors var angle = p1.angleTo( v ); // calculate axis to rotate around. This is the vector that is orthogonal to both align and v var axis = new THREE.Vector3().crossVectors( p1, v ).normalize(); // create quaternion to represent the rotation. Apply quaternion to the object var quat = new THREE.Quaternion().setFromAxisAngle( axis, angle ); var mesh = new THREE.Mesh( this.geometry.spiralSH, this.material.spiralSH );  mesh.orientation = quat;  mesh.position.y = j * interval;  mesh.position.x = i * interval;  mesh.position.z = k * interval; model.parts['spiralSH'] = mesh; model.parts.coreAssy.add( mesh );`
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

Airman wrote:Question, why does the barrel place itself in front of the forward-most component?

Because of this code at the very end of createModel:

Code:
`model.parts.barrel = new THREE.Group();mesh = new THREE.Mesh( this.geometry.barrel, this.material.barrel );model.parts.barrel.add( mesh );  // Position partsvar b = new THREE.Box3();b.setFromObject( model.parts.body );var n = b.max.y * 0.9;b.setFromObject( model.parts.barrel ); model.parts.barrel.scale.copy( this.bodyScale ); model.parts.barrel.position.y = n - b.min.y;`

Specifically, the last line actually sets the barrel position to be at the height of the body (times by 0.9). You can place it anywhere you want, or not have it at all.

Airman wrote:Aligning the springs has been difficult. I’ve tried simple geometry, and quaternions – you’ll no doubt recall the following code. It doesn’t seem to work. I’m surprised the line

Code:
`mesh.orientation = quat;`

doesn’t give me an error. I'm not asking for a review (yet). Do you see any major malfunctions in my thinking? How should one change the orientation of the spring meshes?

There is no orientation property on a THREE.Object3D object. You are looking for the quaternion property. However, you should not reassign that value, as the code above does, but copy the value you want into it.

Code:
`mesh.quaternion.copy( quat );`

I don't know why that is, but I have had trouble in the past because I was assigning a new Vector3 to the position and it would not work. Once I copied in the value, it started working fine. I think references to the position, rotation, quaternion and scale objects are being stored outside of the Object3D itself, so when you assign a new object to them, they don't update those other references. ThreeJS is more than likely doing that for performance reasons, so just go with it and never reassign those properties.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

.

Not exactly progress, these spindly looking guns are not a suggested configuration, they show that something isn’t lining up.

Thanks again for the copy quaternion command - mesh.quaternion.copy( quat );
works fine, all the corner meshes are pointing in the proper directions; except, as you can see im the top left image, things aren’t entirely lining up, something’s askew. All these components work well for the six cardinal points in Revolving gun, but apparently not so well with the eight cornered Cube gun. I’ve added yellow lines at the top right showing the four major ‘cube’ diagonal lines between the eight surrounding spheres positioned at (+/-X,+/-Y,+/-Z), where X =  i * interval;  Y =  j * interval;  Z =  k * interval; interval = 2 * this.body.Radius. I should mention that the Sqrt(3) is involved.

I noticed the barrel code the first time you said the gun barrel was necessary. I’ve routinely not added it without adverse effects but I never messed with its code. I was wondering why you coded the barrel position so. At the present moment, I'm wondering whether the barrel code might somehow inadvertently change the center (0,0,0) y dimension.

I believe all the spheres are in their correct locations, but notice that the beams just touch the spheres – they should all look like the old blue dot wooden ‘matchstick’ shown at 3 oclock from the center in the top two images, behind (0,0,0), opposite the muzzle barrel (0,-this.bodyRadius, 0). The eight beams or sticks are positioned at (+/-X/2,+/-Y/2,+/-Z/2) and oriented between the 8 spheres and (0,0,0). In the second row, the beams were lengthened to 1.2 * their initial lengths. The images are ‘close-ups’ that shows the central ends are not coincident. In the bottom right image, the central ends have been given a tiny radius, showing the small ends of the cylinder geometry do intersect well but not at (0,0,0).

The spiralHelix springs line up better than the barrel cylinder – the outer ends of the springs are centered on the outside spheres, but the central ends of the springs are not centered on (0,0,0), the 8 springs do not meet in four straight line.

I’ll either come up with an adequate explanation/solution or let you know why not. If you have an explanation you could share that would be good too.
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

Airman wrote:I noticed the barrel code the first time you said the gun barrel was necessary. I’ve routinely not added it without adverse effects but I never messed with its code. I was wondering why you coded the barrel position so. At the present moment, I'm wondering whether the barrel code might somehow inadvertently change the center (0,0,0) y dimension.

The barrel is not visually necessary, but its location is. That is, you don't need to show a barrel, but you do need to tell the system where bullets come out of. That is set with the model.muzzle vector.

The reason I created the code above to position the barrel was because I wanted the barrel to be placed at the top of the model. That came from SimpleGunGenerator, and it only contained the spherical, or oval, body and the barrel. Let's walk through the code and see what it is doing.

Code:
`model.parts.barrel = new THREE.Group();mesh = new THREE.Mesh( this.geometry.barrel, this.material.barrel );model.parts.barrel.add( mesh );`

That code is just creating a THREE.Group to contain the barrel, then a THREE.Mesh to visually represent it which is added to the group. It doesn't really need the group, but I was probably thinking ahead and expecting to add more things to it.

Code:
`// Position partsvar b = new THREE.Box3();b.setFromObject( model.parts.body );`

Here we are creating a THREE.Box3 object and then getting the bounds from the body and storing them in that Box3. A Box3 object contains 2 Vector3 objects called min and max, giving you the bounds of the object (or whatever it was set from).

Code:
`var n = b.max.y * 0.9;`

This is just saving the maximum Y value of the body. This will be the top of that object. It is multiplied by 0.9 so that the barrel sinks into the body a little bit.

Code:
`b.setFromObject( model.parts.barrel );`

Now we re-use that Box3 to get the bounds of the barrel itself.

Code:
`model.parts.barrel.scale.copy( this.bodyScale );model.parts.barrel.position.y = n - b.min.y;`

This part is applying a scale to the barrel (it has already been applied to the body separately), I think you added that in and should probably happen before the above line that gets the bounds of the barrel so that the scaling is included in the bounds. Then it sets the Y position of the barrel to the position we found earlier. It subtracts the minimum Y value of the barrel so that it is in the correct place, otherwise it would put the center of the barrel at that position, not its bottom.

With respect to the idea of an origin, you have to be extremely careful what you are talking about. Every time you create an Object3D, or any sub-class, you are creating an origin. Every Object3D has its own origin, or more specifically, a coordinate system.

Then we have the universal origin or the universal coordinate system or world coordinate system. This is absolute 0. This is the coordinate system that everything ends up in, but you don't really see that. ThreeJS takes care of all that for you. But you have to be aware of it or things won't make sense. So let's run though an example to explain it.

We have previously discussed the idea of a scene graph, but haven't delved into how it works too deeply. At the top of the scene graph we have a THREE.Scene object. Everything in that scene is stored underneath that Scene object. So we have to understand what it means to be underneath another node in the graph.

The first thing to be aware of is that THREE.Scene extends from THREE.Object3D. So it is just like any other Object3D and has its own coordinate system. However, we can consider the Scene to be the top coordinate system. It isn't, really, it is not the universal coordinate system, but it is as close as we usually need to be. It is possible to have multiple Scene objects being rendered, but rare, and beyond this discussion.

Actually, scratch that, I'm going to explicitly use the universal coordinate system. Since the Scene is an Object3D, we have to use it.

So let's start to build a scene graph:

Code:
`UCS - universal coordinate system  Scene`

That isn't very interesting, but it actually would render something if we set a background on that Scene. So let's add some more nodes to it and see how they change each other.

Code:
`UCS  Scene    Group1      Point1      Point2    Group2      Point3`

That gives us a Scene containing 2 THREE.Group objects, called Group1 and Group2. Each group then contains some points (for simplicity). If we rendered that, all 3 points would be on top of each other at the origin. The universal origin. Actually, every origin, because none of the nodes have changed their positions. So let's change some positions.

Code:
`UCS  Scene    Group1      Point1: 1, 0, 0      Point2: 0, 1, 0    Group2      Point3: 0, 0, 1`

So now we have 3 points with each 1 unit along each dimension, X, Y and Z. The positions of each point remain the same across all coordinate systems. We could remove the groups and put the points into the Scene and nothing would change.

Code:
`UCS  Scene    Group1: 0, 0, 1      Point1: 1, 0, 0      Point2: 0, 1, 0    Group2: 1, 0, 0      Point3: 0, 0, 1`

Now we have specified a position for each group. How does that change the points?

The scene graph is calculated from the top down to the bottom. This is all calculated into matrices so that the position, rotation and scale or every node can be incorporated into a single matrix for that node. This is known as the world matrix. You can actually access that in THREE with the Object3D.matrixWorld property, but you usually don't need to. It comes in handy when trying to find the relationship between 2 nodes that can be in very distant parts of the scene graph.

We start with the UCS, which doesn't actually have any position, rotation or scale, so we end up with an identify matrix.

Then we look at the Scene. We take the world matrix from the UCS, and multiply in the values from the Scene. In this case, the Scene also has no values, so we end up with another identity matrix.

Now we look at Group1, which finally has some values. After multiplying its values into the world matrix of Group1, we end up with a matrix that translates by 1 unit in the Z dimension.

Point1 and Point2 are underneath Group1, so we start with Group1's world matrix and multiply in Point1's values to get a new matrix that translates by 1 unit in X and Z. So in the universal coordinate system, Point1 is actually located at (1, 0, 1). We do the same with Point2's values and end up with a matrix that translates by 1 unit in Y and Z. Placing Point2 at (0, 1, 1).

We do the same for Group2, which is underneath Scene, so we start with the Scene world matrix and multiply in Group2's values to get a matrix that translates by 1 unit in the X dimension.

Point3 takes Group2's world matrix and multiplies in its own values to get a matrix that translates by 1 unit in X and Z. Therefore, Point3 will be placed at (1, 0, 1).

So you can see that every node has its own coordinate system, but that is effected by all nodes above it, in a direct line to the top, in the scene graph.

When you ask if something is at 0, 0, 0, I have to know which coordinate system you are talking about. You could say "with respect to Group1, what is the position of Point2", and I would answer (0, 1, 0). If you asked "with respect to Scene, what is the position of Point2", I was say (0, 1, 1). If you asked "what is the position of Point3 with respect to Group1", I would say that you have the scene graph mixed up. However, we actually can calculate the position of Point3 with respect to Group1. It isn't difficult, but it isn't the right question for this type of operation. That is, when building a scene graph, you should only be looking at what is in the direct line to the top to figure out where any particular node is going to end up. When analyzing a scene graph, then you need to figure out where things are in relation to other things that may be in completely different parts of the scene graph, so you fall back to the world coordinate system to do it because that is where we have comparable values.

So, after all that, you are correct that the barrel is moving the origin of the complete model (or its highest node), but it is not moving the origin of the body, because that has its own origin. Here is that scene graph:

Code:
`...  model.object3D    Group      body      barrel`

My guess is that you are placing the markers into either Group or model.object3D, rather than body (or its equivalent in your code), which is where the bars are being put. That changes the origin slightly because Group contains both body and barrel and it is centered on that combination.

Here is the code that does the centering:

Code:
`var grp = new THREE.Group();grp.add( model.parts.coreAssy, model.parts.cage, model.parts.barrel );b.setFromObject( grp );grp.position.x = -b.min.x - ( b.max.x - b.min.x )/2;grp.position.y = -b.min.y - ( b.max.y - b.min.y );///2;grp.position.z = -b.min.z - ( b.max.z - b.min.z )/2;model.object3D.add( grp );`

It is centering in the X and Z, but not in Y. It is placing the top of the model at Y=0.

I suggest you get your scene graph in order and make sure that you are using the correct groups. Especially when you are adding in markers to ensure that things are where you think that they should be. Write out the graph like I have above and you should be able to see where something is not being put into the correct group.

And feel free to get rid of that barrel if you don't want it. It is only the muzzle that needs to be set (unless 0,0,0 is where you want it).

I also apologize if I am using the wrong gun terms. Feel free to correct me.

Nevyn

Posts : 1744
Join date : 2014-09-11

## Re: Virtual Scattering Application

Airman wrote. The spiralHelix springs line up better than the barrel cylinder – the outer ends of the springs are centered on the outside spheres, but the central ends of the springs are not centered on (0,0,0), the 8 springs do not meet in four straight line(s). (sic)

I’ll either come up with an adequate explanation/solution or let you know why not. If you have an explanation you could share that would be good too(.) (sic^2)

Nevyn wrote. My guess is that you are placing the markers into either Group or model.object3D, rather than body (or its equivalent in your code), which is where the bars are being put. That changes the origin slightly because Group contains both body and barrel and it is centered on that combination.
Code:
`...  model.object3D    Group      body      barrel`

The Scene Graph. This is one of those occasions where I was stunned for a day - overwhelmed by my ignorance. You've provided a great deal of detailed information, a wonderful exposé on the subject. I greatly appreciate the lesson.

Code:
`...model.object3D   model.parts.coreAssy      model.parts.cage       model.parts.body            grp       model.parts.barrel // the muzzle barrel `

So, I’ve been reviewing and mixing things around. Above is the Cube gun’s current scene graph – I think. Object3D contains all the scene’s THREE groups and meshes. model.parts.coreAssy, model.parts.cage, and model.parts.body are added to model.object3D. The muzzle barrel – I have no idea what the correct terminology may be, it’s not important - model.parts.barrel is first added to grp. grp is then added to object 3D.

Code:
`// 8 thin beams, sticks or bars, which are reoriented but are not aligned – the main error being considered var mesh = new THREE.Mesh( this.geometry.barrel2, this.material.barrel2 );  mesh.quaternion.copy( quat );  mesh.position.y = j * interval/2 + constY; //  var constY = 0; mesh.position.x = i * interval/2 ;  mesh.position.z = k * interval/2 ; model.parts['spiralSH'] = mesh; model.parts.coreAssy.add( mesh );  //model.parts.cage.add( mesh );  //model.parts.body.add( mesh ); // no stick altRot  //grp.add( mesh ); The small spheres are moved fwd, bent sticks, no stick altRot //model.object3D.add( mesh );`

In addition to the barrel, there are the aforementioned eight not aligned measuring rod markers, 8 also not aligned springs and 8 spheres. The spheres are positioned according to i,j, and k coordinates, while the markers and springs are reoriented by quaternions. At no time did I alter the bent geometry. So I became more systematic. I methodically added each mesh to each group until I tried ‘all the combinations’.

Code:
`var interval = 5 ; // Cubic Array of eight measuring rod markers for ( var i = -1; i < 2; i = i + 2 ) {   for ( var j = -1; j < 2; j = j + 2 ) {      for ( var k = -1; k < 2; k = k + 2 ) {         var p1 = new THREE.Vector3( 0, -1, 0 );         var p2 = new THREE.Vector3( -i * interval, -j * interval, -k * interval );         var v = new THREE.Vector3().subVectors( p1, p2 );          var angle = p1.angleTo( v );         var axis = new THREE.Vector3().crossVectors( p1, v ).normalize();         var quat = new THREE.Quaternion().setFromAxisAngle( axis, angle );          var mesh = new THREE.Mesh( this.geometry.barrel2, this.material.barrel2 );         mesh.quaternion.copy( quat );          mesh.position.x = interval * i ;          mesh.position.y = interval * j ;          mesh.position.z = interval * k ;          model.parts.body.add( mesh );         }      } };`

At no time did I alter the unfortunate bend problem. I was forced to test a previous gun, I removed the six Simple gun spheres and other meshes of the Simple Array gun and replaced them with the Cubic Array of eight measuring rod markers - code above - image below.

Have I done it again? The markers are 'bent' - not coincident - in exactly the same way as in Cube gun, like the firing pattern and the gun alignment problem?
.

Last edited by LongtimeAirman on Tue Jul 23, 2019 6:04 pm; edited 1 time in total (Reason for editing : Saw and corrected the dreaded http slash slash error in mesh.position.y)

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

.

Status Update. Took a couple of days off. Back to it, fresh eyes let me see this configuration of the 'Cube gun', where the six spheres that traveled along the blue tracks are replaced with 8 spheres that are counter rotating with/between the octants. Definitely worth consideration.
.

LongtimeAirman

Posts : 1387
Join date : 2014-08-10

## Re: Virtual Scattering Application

I fixed the gun alignment issue. It was caused by my bad math.

Added a control to set the gun accuracy. More specifically, it sets the maximum allowed angle, from a perfect shot at the target, that the gun's own accuracy can set. That still allows each individual gun to have its own accuracy setting while allowing the user to have some control over it.

Added a control to set the gun firing rate when auto-firing. You can generate a lot of bullets. I haven't seen any problems so far, but it does depend on the system running the app. Every bullet is CPU bound, rather than GPU bound which would be much faster to process. The rendering of the bullets is GPU bound, but not their velocity or collision calculations, unfortunately.

I think that fixes the main problems with the app, setting up the basis for recording data from it. I also think that it needs some sort of time scale for the user, but I'm not sure how to show it yet.

Nevyn

Posts : 1744
Join date : 2014-09-11