<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.2//EN" "https://www.web3d.org/specifications/x3d-3.2.dtd">
<![CDATA[
ecmascript: function initialize() { CheckInit(); } function CheckInit() { if(!bInitialized) { bInitialized= true; // Init() may call other functions that call CheckInit(). In that case it's better the flag is already set, otherwise an endless loop would occur. Init(); } } function Init() { destination= initial_destination; Buffer.length= cNumSupports; Buffer[0]= initial_destination; for(var C= 1; C<Buffer.length; C++ ) Buffer[C]= initial_value; previousValue= initial_value; cStepTime= duration / cNumSupports; } function set_destination(Dest, Now) { CheckInit(); destination= Dest; // Somehow we assign to Buffer[-1] and wait untill this gets shifted into the real buffer. // Would we assign to Buffer[0] instead, we'd have no delay, but this would create a jump in the // output because Buffer[0] is associated with a value in the past. UpdateBuffer(Now); } function Tick(Now) { CheckInit(); if(!BufferEndTime) { BufferEndTime= Now; // first event we received, so we are in the initialization phase. value_changed= initial_value; return; } var Frac= UpdateBuffer(Now); // Frac is a value in 0 <= Frac < 1. // Now we can calculate the output. // This means we calculate the delta between each entry in Buffer and its previous // entries, calculate the step response of each such step and add it to form the output. // The oldest vaule Buffer[Buffer.length - 1] needs some extra thought, because it has // no previous value. More exactly, we haven't stored a previous value anymore. // However, the step response of that missing previous value has already reached its // destination, so we can - would we have that previous value - use this as a start point // for adding the step responses. // Actually UpdateBuffer(.) maintains this value in var Output= previousValue; var DeltaIn= Buffer[Buffer.length - 1].subtract(previousValue); var DeltaOut= DeltaIn.multiply(StepResponse((Buffer.length - 1 + Frac) * cStepTime)); Output= Output.add(DeltaOut); for(var C= Buffer.length - 2; C>=0; C-- ) { var DeltaIn= Buffer[C].subtract(Buffer[C + 1]); var DeltaOut= DeltaIn.multiply(StepResponse((C + Frac) * cStepTime)); Output= Output.add(DeltaOut); } if(Output != value_changed) value_changed= Output; } function UpdateBuffer(Now) { var Frac= (Now - BufferEndTime) / cStepTime; // is normally < 1. When it has grown to be larger than 1, we have to shift the array because the step response // of the oldest entry has already reached its destination, and it's time for a newer entry. // has already reached it // In the case of a very low frame rate, or a very short cStepTime we may need to shift by more than one entry. if(Frac >= 1) { var NumToShift= Math.floor(Frac); Frac-= NumToShift; if(NumToShift < Buffer.length) { // normal case. previousValue= Buffer[Buffer.length - NumToShift]; for(var C= Buffer.length - 1; C>=NumToShift; C-- ) Buffer[C]= Buffer[C - NumToShift]; for(var C= 0; C<NumToShift; C++ ) { // Hmm, we have a destination value, but don't know how it has // reached the current state. // Therefore we do a linear interpolation from the latest value in the buffer to destination. var Alpha= C / NumToShift; Buffer[C]= Buffer[NumToShift].multiply(Alpha).add(destination.multiply((1 - Alpha))); } }else { // degenerated case: // // We have a _VERY_ low frame rate... // we can only guess how we should fill the array. // Maybe we could write part of a linear interpolation // from Buffer[0] to destination, that goes from BufferEndTime to Now // (possibly only the end of the interpolation is to be written), // but if we rech here we are in a very degenerate case... // Thus we just write destination to the buffer. previousValue= NumToShift == Buffer.length? Buffer[0] : destination; for(var C= 0; C<Buffer.length; C++ ) Buffer[C]= destination; } BufferEndTime+= NumToShift * cStepTime; } return Frac; } function StepResponse(t) { if(t < 0) return 0; if(t > duration) return 1; // When optimizing for speed, the above two if(.) cases can be omitted, // as this funciton will not be called for values outside of 0..duration. return StepResponseCore(t / duration); } // This function defines the shape of how the output responds to the input. // It must accept values for T in the range 0 <= T <= 1. // In order to create a smooth animation, it should return 0 for T == 0, // 1 for T == 1 and be sufficient smooth in the range 0 <= T <= 1. // It should be optimized for speed, in order for high performance. It's // executed Buffer.length + 1 times each simulation tick. function StepResponseCore(T) { return .5 - .5 * Math.cos(T * Math.PI); } // The following functions are not used. They provide other responses (for fun). function StepResponseCoreF(T) { var cTau= .3; var cFrequency= 2.5; return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T) * (1 - T); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI)); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI))* (.5 + .5 * Math.cos(T * Math.PI)); } function StepResponseCoreE(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cFrequency= 2.5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.sin(Math.sqrt(1 - T) * Math.PI/2); return A * .8 + B * .2; } function StepResponseCoreD(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cFrequency= 2.5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.sin((1 - T) * Math.PI/2); return A * .8 + B * .2; } function StepResponseCoreC(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T); return A * .8 + B * .2; } function StepResponseCoreB(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) /** Math.exp(-T / cTau)*/ * (1 - T); return A * .8 + B * .2; } function StepResponseCoreA(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) /** Math.exp(-T / cTau)*/ * (1 - T); var Alpha= .2 * T; return A * (1 - Alpha) + B * Alpha; }
]]>
<![CDATA[
ecmascript: function initialize() { CheckInit(); } function CheckInit() { if(!bInitialized) { bInitialized= true; // Init() may call other functions that call CheckInit(). In that case it's better the flag is already set, otherwise an endless loop would occur. Init(); } } function Init() { destination= initial_destination; Buffer.length= cNumSupports; Buffer[0]= initial_destination; for(var C= 1; C<Buffer.length; C++ ) Buffer[C]= initial_value; previousValue= initial_value; cStepTime= duration / cNumSupports; } function set_destination(Dest, Now) { CheckInit(); destination= Dest; // Somehow we assign to Buffer[-1] and wait untill this gets shifted into the real buffer. // Would we assign to Buffer[0] instead, we'd have no delay, but this would create a jump in the // output because Buffer[0] is associated with a value in the past. UpdateBuffer(Now); } function Tick(Now) { CheckInit(); if(!BufferEndTime) { BufferEndTime= Now; // first event we received, so we are in the initialization phase. value_changed= initial_value; return; } var Frac= UpdateBuffer(Now); // Frac is a value in 0 <= Frac < 1. // Now we can calculate the output. // This means we calculate the delta between each entry in Buffer and its previous // entries, calculate the step response of each such step and add it to form the output. // The oldest vaule Buffer[Buffer.length - 1] needs some extra thought, because it has // no previous value. More exactly, we haven't stored a previous value anymore. // However, the step response of that missing previous value has already reached its // destination, so we can - would we have that previous value - use this as a start point // for adding the step responses. // Actually UpdateBuffer(.) maintains this value in var Output= previousValue; var DeltaIn= previousValue.inverse().multiply(Buffer[Buffer.length - 1]); Output= Output.slerp(Output.multiply(DeltaIn), StepResponse((Buffer.length - 1 + Frac) * cStepTime)); for(var C= Buffer.length - 2; C>=0; C-- ) { var DeltaIn= Buffer[C + 1].inverse().multiply(Buffer[C]); Output= Output.slerp(Output.multiply(DeltaIn), StepResponse((C + Frac) * cStepTime)); } if(Output != value_changed) value_changed= Output; } function UpdateBuffer(Now) { var Frac= (Now - BufferEndTime) / cStepTime; // is normally < 1. When it has grown to be larger than 1, we have to shift the array because the step response // of the oldest entry has already reached its destination, and it's time for a newer entry. // has already reached it // In the case of a very low frame rate, or a very short cStepTime we may need to shift by more than one entry. if(Frac >= 1) { var NumToShift= Math.floor(Frac); Frac-= NumToShift; if(NumToShift < Buffer.length) { // normal case. previousValue= Buffer[Buffer.length - NumToShift]; for(var C= Buffer.length - 1; C>=NumToShift; C-- ) Buffer[C]= Buffer[C - NumToShift]; for(var C= 0; C<NumToShift; C++ ) { // Hmm, we have a destination value, but don't know how it has // reached the current state. // Therefore we do a linear interpolation from the latest value in the buffer to destination. Buffer[C]= destination.slerp(Buffer[NumToShift], C / NumToShift); } }else { // degenerated case: // // We have a _VERY_ low frame rate... // we can only guess how we should fill the array. // Maybe we could write part of a linear interpolation // from Buffer[0] to destination, that goes from BufferEndTime to Now // (possibly only the end of the interpolation is to be written), // but if we rech here we are in a very degenerate case... // Thus we just write destination to the buffer. previousValue= NumToShift == Buffer.length? Buffer[0] : destination; for(var C= 0; C<Buffer.length; C++ ) Buffer[C]= destination; } BufferEndTime+= NumToShift * cStepTime; } return Frac; } function StepResponse(t) { if(t < 0) return 0; if(t > duration) return 1; // When optimizing for speed, the above two if(.) cases can be omitted, // as this funciton will not be called for values outside of 0..duration. return StepResponseCore(t / duration); } // This function defines the shape of how the output responds to the input. // It must accept values for T in the range 0 <= T <= 1. // In order to create a smooth animation, it should return 0 for T == 0, // 1 for T == 1 and be sufficient smooth in the range 0 <= T <= 1. // It should be optimized for speed, in order for high performance. It's // executed Buffer.length + 1 times each simulation tick. function StepResponseCore(T) { return .5 - .5 * Math.cos(T * Math.PI); } // The following functions are not used. They provide other responses (for fun). function StepResponseCoreG(T) { var cTau= .3; var cFrequency= 5; return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI)); } function StepResponseCoreF(T) { var cTau= .3; var cFrequency= 2.5; // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T) * (1 - T); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI)); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI))* (.5 + .5 * Math.cos(T * Math.PI)); } function StepResponseCoreE(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cFrequency= 2.5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.sin(Math.sqrt(1 - T) * Math.PI/2); return A * .8 + B * .2; } function StepResponseCoreD(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cFrequency= 2.5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.sin((1 - T) * Math.PI/2); return A * .8 + B * .2; } function StepResponseCoreC(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T); return A * .8 + B * .2; } function StepResponseCoreB(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) /** Math.exp(-T / cTau)*/ * (1 - T); return A * .8 + B * .2; } function StepResponseCoreA(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) /** Math.exp(-T / cTau)*/ * (1 - T); var Alpha= .2 * T; return A * (1 - Alpha) + B * Alpha; }
]]>
<![CDATA[
ecmascript: function initialize() { CheckInit(); } function CheckInit() { if(!bInitialized) { bInitialized= true; // Init() may call other functions that call CheckInit(). In that case it's better the flag is already set, otherwise an endless loop would occur. Init(); } } function Init() { destination= initial_destination; Buffer.length= cNumSupports; Buffer[0]= initial_destination; for(var C= 1; C<Buffer.length; C++ ) Buffer[C]= initial_value; previousValue= initial_value; cStepTime= duration / cNumSupports; } function set_destination(Dest, Now) { CheckInit(); destination= Dest; // Somehow we assign to Buffer[-1] and wait untill this gets shifted into the real buffer. // Would we assign to Buffer[0] instead, we'd have no delay, but this would create a jump in the // output because Buffer[0] is associated with a value in the past. UpdateBuffer(Now); } function Tick(Now) { CheckInit(); if(!BufferEndTime) { BufferEndTime= Now; // first event we received, so we are in the initialization phase. value_changed= initial_value; return; } var Frac= UpdateBuffer(Now); // Frac is a value in 0 <= Frac < 1. // Now we can calculate the output. // This means we calculate the delta between each entry in Buffer and its previous // entries, calculate the step response of each such step and add it to form the output. // The oldest vaule Buffer[Buffer.length - 1] needs some extra thought, because it has // no previous value. More exactly, we haven't stored a previous value anymore. // However, the step response of that missing previous value has already reached its // destination, so we can - would we have that previous value - use this as a start point // for adding the step responses. // Actually UpdateBuffer(.) maintains this value in var Output= previousValue; var DeltaIn= Buffer[Buffer.length - 1].subtract(previousValue); var DeltaOut= DeltaIn.multiply(StepResponse((Buffer.length - 1 + Frac) * cStepTime)); Output= Output.add(DeltaOut); for(var C= Buffer.length - 2; C>=0; C-- ) { var DeltaIn= Buffer[C].subtract(Buffer[C + 1]); var DeltaOut= DeltaIn.multiply(StepResponse((C + Frac) * cStepTime)); Output= Output.add(DeltaOut); } if(Output != value_changed) value_changed= Output; } function UpdateBuffer(Now) { var Frac= (Now - BufferEndTime) / cStepTime; // is normally < 1. When it has grown to be larger than 1, we have to shift the array because the step response // of the oldest entry has already reached its destination, and it's time for a newer entry. // has already reached it // In the case of a very low frame rate, or a very short cStepTime we may need to shift by more than one entry. if(Frac >= 1) { var NumToShift= Math.floor(Frac); Frac-= NumToShift; if(NumToShift < Buffer.length) { // normal case. previousValue= Buffer[Buffer.length - NumToShift]; for(var C= Buffer.length - 1; C>=NumToShift; C-- ) Buffer[C]= Buffer[C - NumToShift]; for(var C= 0; C<NumToShift; C++ ) { // Hmm, we have a destination value, but don't know how it has // reached the current state. // Therefore we do a linear interpolation from the latest value in the buffer to destination. var Alpha= C / NumToShift; Buffer[C]= Buffer[NumToShift].multiply(Alpha).add(destination.multiply((1 - Alpha))); } }else { // degenerated case: // // We have a _VERY_ low frame rate... // we can only guess how we should fill the array. // Maybe we could write part of a linear interpolation // from Buffer[0] to destination, that goes from BufferEndTime to Now // (possibly only the end of the interpolation is to be written), // but if we rech here we are in a very degenerate case... // Thus we just write destination to the buffer. previousValue= NumToShift == Buffer.length? Buffer[0] : destination; for(var C= 0; C<Buffer.length; C++ ) Buffer[C]= destination; } BufferEndTime+= NumToShift * cStepTime; } return Frac; } function StepResponse(t) { if(t < 0) return 0; if(t > duration) return 1; // When optimizing for speed, the above two if(.) cases can be omitted, // as this funciton will not be called for values outside of 0..duration. return StepResponseCore(t / duration); } // This function defines the shape of how the output responds to the input. // It must accept values for T in the range 0 <= T <= 1. // In order to create a smooth animation, it should return 0 for T == 0, // 1 for T == 1 and be sufficient smooth in the range 0 <= T <= 1. // It should be optimized for speed, in order for high performance. It's // executed Buffer.length + 1 times each simulation tick. function StepResponseCore(T) { return .5 - .5 * Math.cos(T * Math.PI); } // The following functions are not used. They provide other responses (for fun). function StepResponseCoreF(T) { var cTau= .3; var cFrequency= 2.5; return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T) * (1 - T); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI)); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI))* (.5 + .5 * Math.cos(T * Math.PI)); } function StepResponseCoreE(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cFrequency= 2.5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.sin(Math.sqrt(1 - T) * Math.PI/2); return A * .8 + B * .2; } function StepResponseCoreD(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cFrequency= 2.5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.sin((1 - T) * Math.PI/2); return A * .8 + B * .2; } function StepResponseCoreC(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T); return A * .8 + B * .2; } function StepResponseCoreB(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) /** Math.exp(-T / cTau)*/ * (1 - T); return A * .8 + B * .2; } function StepResponseCoreA(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) /** Math.exp(-T / cTau)*/ * (1 - T); var Alpha= .2 * T; return A * (1 - Alpha) + B * Alpha; }
]]>
<![CDATA[
ecmascript: function initialize() { CheckInit(); } function CheckInit() { if(!bInitialized) { bInitialized= true; // Init() may call other functions that call CheckInit(). In that case it's better the flag is already set, otherwise an endless loop would occur. Init(); } } function Init() { destinationPos= initial_destinationPos; destinationOri= initial_destinationOri; BufferPos.length= BufferOri.length= cNumSupports; BufferPos[0]= initial_destinationPos; BufferOri[0]= initial_destinationOri; for(var C= 1; C<BufferPos.length; C++ ) { BufferPos[C]= initial_valuePos; BufferOri[C]= initial_valueOri; } previousValuePos= initial_valuePos; previousValueOri= initial_valueOri; cStepTime= duration / cNumSupports; } function set_destinationPos(Dest, Now) { CheckInit(); destinationPos= Dest; // Somehow we assign to Buffer[-1] and wait untill this gets shifted into the real buffer. // Would we assign to Buffer[0] instead, we'd have no delay, but this would create a jump in the // output because Buffer[0] is associated with a value in the past. //UpdateBuffer(Now); } function set_destinationOri(Dest, Now) { CheckInit(); destinationOri= Dest; // Somehow we assign to Buffer[-1] and wait untill this gets shifted into the real buffer. // Would we assign to Buffer[0] instead, we'd have no delay, but this would create a jump in the // output because Buffer[0] is associated with a value in the past. //UpdateBuffer(Now); } function Tick(Now) { CheckInit(); if(!BufferEndTime) { BufferEndTime= Now; // first event we received, so we are in the initialization phase. valuePos_changed= initial_valuePos; valueOri_changed= initial_valueOri; return; } var Frac= UpdateBuffer(Now); // Frac is a value in 0 <= Frac < 1. // Now we can calculate the output. // This means we calculate the delta between each entry in Buffer and its previous // entries, calculate the step response of each such step and add it to form the output. // The oldest vaule Buffer[Buffer.length - 1] needs some extra thought, because it has // no previous value. More exactly, we haven't stored a previous value anymore. // However, the step response of that missing previous value has already reached its // destination, so we can - would we have that previous value - use this as a start point // for adding the step responses. // Actually UpdateBuffer(.) maintains this value in var OutputPos= previousValuePos; var OutputOri= previousValueOri; var DeltaInPos= BufferPos[BufferPos.length - 1].subtract(previousValuePos); var DeltaInOri= previousValueOri.inverse().multiply(BufferOri[BufferOri.length - 1]); var DeltaOutPos= DeltaInPos.multiply(StepResponse((BufferPos.length - 1 + Frac) * cStepTime)); OutputPos= OutputPos.add(DeltaOutPos); OutputOri= OutputOri.slerp(OutputOri.multiply(DeltaInOri), StepResponse((BufferOri.length - 1 + Frac) * cStepTime)); for(var C= BufferPos.length - 2; C>=0; C-- ) { var DeltaInPos= BufferPos[C].subtract(BufferPos[C + 1]); var DeltaInOri= BufferOri[C + 1].inverse().multiply(BufferOri[C]); var DeltaOutPos= DeltaInPos.multiply(StepResponse((C + Frac) * cStepTime)); OutputPos= OutputPos.add(DeltaOutPos); OutputOri= OutputOri.slerp(OutputOri.multiply(DeltaInOri), StepResponse((C + Frac) * cStepTime)); } if(OutputPos != valuePos_changed) valuePos_changed= OutputPos; if(OutputOri != valueOri_changed) valueOri_changed= OutputOri; } function UpdateBuffer(Now) { var Frac= (Now - BufferEndTime) / cStepTime; // is normally < 1. When it has grown to be larger than 1, we have to shift the array because the step response // of the oldest entry has already reached its destination, and it's time for a newer entry. // has already reached it // In the case of a very low frame rate, or a very short cStepTime we may need to shift by more than one entry. if(Frac >= 1) { var NumToShift= Math.floor(Frac); Frac-= NumToShift; if(NumToShift < BufferPos.length) { // normal case. previousValuePos= BufferPos[BufferPos.length - NumToShift]; previousValueOri= BufferOri[BufferOri.length - NumToShift]; for(var C= BufferPos.length - 1; C>=NumToShift; C-- ) { BufferPos[C]= BufferPos[C - NumToShift]; BufferOri[C]= BufferOri[C - NumToShift]; } for(var C= 0; C<NumToShift; C++ ) { // Hmm, we have a destination value, but don't know how it has // reached the current state. // Therefore we do a linear interpolation from the latest value in the buffer to destination. var Alpha= C / NumToShift; BufferPos[C]= BufferPos[NumToShift].multiply(Alpha).add(destinationPos.multiply((1 - Alpha))); BufferOri[C]= destinationOri.slerp(BufferOri[NumToShift], Alpha); } }else { // degenerated case: // // We have a _VERY_ low frame rate... // we can only guess how we should fill the array. // Maybe we could write part of a linear interpolation // from Buffer[0] to destination, that goes from BufferEndTime to Now // (possibly only the end of the interpolation is to be written), // but if we rech here we are in a very degenerate case... // Thus we just write destination to the buffer. previousValuePos= NumToShift == BufferPos.length? BufferPos[0] : destinationPos; previousValueOri= NumToShift == BufferOri.length? BufferOri[0] : destinationOri; for(var C= 0; C<BufferPos.length; C++ ) { BufferPos[C]= destinationPos; BufferOri[C]= destinationOri; } } BufferEndTime+= NumToShift * cStepTime; } return Frac; } function StepResponse(t) { if(t < 0) return 0; if(t > duration) return 1; // When optimizing for speed, the above two if(.) cases can be omitted, // as this funciton will not be called for values outside of 0..duration. return StepResponseCore(t / duration); } // This function defines the shape of how the output responds to the input. // It must accept values for T in the range 0 <= T <= 1. // In order to create a smooth animation, it should return 0 for T == 0, // 1 for T == 1 and be sufficient smooth in the range 0 <= T <= 1. // It should be optimized for speed, in order for high performance. It's // executed Buffer.length + 1 times each simulation tick. function StepResponseCore(T) { return .5 - .5 * Math.cos(T * Math.PI); } // The following functions are not used. They provide other responses (for fun). function StepResponseCoreF(T) { var cTau= .3; var cFrequency= 2.5; return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T) * (1 - T); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI)); // return 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (.5 + .5 * Math.cos(T * Math.PI))* (.5 + .5 * Math.cos(T * Math.PI)); } function StepResponseCoreE(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cFrequency= 2.5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.sin(Math.sqrt(1 - T) * Math.PI/2); return A * .8 + B * .2; } function StepResponseCoreD(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cFrequency= 2.5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.sin((1 - T) * Math.PI/2); return A * .8 + B * .2; } function StepResponseCoreC(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) * Math.exp(-T / cTau) * (1 - T); return A * .8 + B * .2; } function StepResponseCoreB(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) /** Math.exp(-T / cTau)*/ * (1 - T); return A * .8 + B * .2; } function StepResponseCoreA(T) { var A= .5 - .5 * Math.cos(T * Math.PI); var cTau= .3; var cFrequency= 5; var B= 1 - Math.cos(T * 2 * Math.PI * cFrequency) /** Math.exp(-T / cTau)*/ * (1 - T); var Alpha= .2 * T; return A * (1 - Alpha) + B * Alpha; }
]]>
<![CDATA[
ecmascript: function initialize() { isLoaded= true; }
]]>
<![CDATA[
ecmascript: function StartTimer() { if(IsCortona) return; if(!needTimer) { lastTick= 0; needTimer= true; } } function StopTimer() { if(IsCortona) return; if(needTimer) { needTimer= false; } } function initialize() { CheckInit(); } function CheckInit() { if(!bInitialized) { bInitialized= true; Init(); } } function Init() { IsCortona= false && Browser.getName().indexOf('Cortona') != -1; bNeedToTakeFirstInput= takeFirstInput; tau= effs.tau; set_value(initial_value); if(IsCortona) needTimer= true; else needTimer= input.x != initial_value.x || input.y != initial_value.y || input.z != initial_value.z ; } function set_tau(t) { CheckInit(); tau= t; } function set_destination(i) { CheckInit(); if(bNeedToTakeFirstInput) { bNeedToTakeFirstInput= false; set_value(i); } if(i != input) { input= i; StartTimer(); } } function set_value(o) { CheckInit(); bNeedToTakeFirstInput= false; value1= value2= value3= value4= value5= o; value_changed= o; UpdateReached(); StartTimer(); } function tick(now) { CheckInit(); if(!lastTick) { lastTick= now; return; } var delta= now - lastTick; lastTick= now; var alpha= Math.exp(-delta / tau); if(bNeedToTakeFirstInput) // then don't do any processing. return; value1= order > 0 && tau ? input .add(value1.subtract(input ).multiply(alpha)) : input; value2= order > 1 && tau ? value1.add(value2.subtract(value1).multiply(alpha)) : value1; value3= order > 2 && tau ? value2.add(value3.subtract(value2).multiply(alpha)) : value2; value4= order > 3 && tau ? value3.add(value4.subtract(value3).multiply(alpha)) : value3; value5= order > 4 && tau ? value4.add(value5.subtract(value4).multiply(alpha)) : value4; var dist= GetDist(); if(dist < eps) { value1= value2= value3= value4= value5= input; value_changed= input; UpdateReached2(dist); StopTimer(); return; } value_changed= value5; UpdateReached2(dist); } function GetDist() { var dist= value1.subtract(input).length(); if(order > 1) { var dist2= value2.subtract(value1).length(); if( dist2 > dist) dist= dist2; } if(order > 2) { var dist3= value3.subtract(value2).length(); if( dist3 > dist) dist= dist3; } if(order > 3) { var dist4= value4.subtract(value3).length(); if( dist4 > dist) dist= dist4; } if(order > 4) { var dist5= value5.subtract(value4).length(); if( dist5 > dist) dist= dist5; } return dist; } function UpdateReached() { return UpdateReached2(GetDist()); } function UpdateReached2(Dist) { if(reached) { if(Dist > reachThreshold) reached= false; }else { if(Dist <= reachThreshold) reached= true; } }
]]>
Event Graph ROUTE Table entries with 6 ROUTE connections total, showing X3D event-model relationships for this scene.
Each row shows an event cascade that may occur during a single timestamp interval between frame renderings, as part of the X3D execution model.
The following
ROUTE
begins an event-routing loop! Loop occurs at nodeDepth=3.
ROUTE Timer_PositionDamper.time TO Worker.tick |
||||||||||||||||||||||
Timer_PositionDamper
TimeSensor time SFTime |
Worker
Script tick SFTime |
then |
Worker
Script needTimer SFBool |
Timer_PositionDamper
TimeSensor enabled SFBool |
then |
Timer_PositionDamper
TimeSensor time SFTime |
Worker
Script tick SFTime |
then |
Worker
Script needTimer SFBool |
Timer_PositionDamper
TimeSensor enabled SFBool |
then |
Timer_PositionDamper
TimeSensor time SFTime |
Worker
Script tick SFTime |
then |
Worker
Script needTimer SFBool |
Timer_PositionDamper
TimeSensor enabled SFBool |
Tmer_OrientationChaser
TimeSensor time SFTime |
ScreenPositionDamper_OrientationChaser
Script Tick SFTime |
Tmer_PlacementChaser
TimeSensor time SFTime |
ScreenPositionDamper_PlacementChaser
Script Tick SFTime |
Tmer_Position2fChaser
TimeSensor time SFTime |
ScreenPositionDamper_Position2fChaser
Script Tick SFTime |
Tmer_PositionChaser
TimeSensor time SFTime |
ScreenPositionDamper_PositionChaser
Script Tick SFTime |
LastNode
Script |
No ROUTE connection found for output from this node. |
ScreenPositionDamper_OrientationChaser
Script |
No ROUTE connection found for output from this node. |
ScreenPositionDamper_PlacementChaser
Script |
No ROUTE connection found for output from this node. |
ScreenPositionDamper_Position2fChaser
Script |
No ROUTE connection found for output from this node. |
ScreenPositionDamper_PositionChaser
Script |
No ROUTE connection found for output from this node. |
The following
ROUTE
begins an event-routing loop! Loop occurs at nodeDepth=3.
ROUTE Worker.needTimer TO Timer_PositionDamper.enabled |
||||||||||||||||||||||
Worker
Script needTimer SFBool |
Timer_PositionDamper
TimeSensor enabled SFBool |
then |
Timer_PositionDamper
TimeSensor time SFTime |
Worker
Script tick SFTime |
then |
Worker
Script needTimer SFBool |
Timer_PositionDamper
TimeSensor enabled SFBool |
then |
Timer_PositionDamper
TimeSensor time SFTime |
Worker
Script tick SFTime |
then |
Worker
Script needTimer SFBool |
Timer_PositionDamper
TimeSensor enabled SFBool |
then |
Timer_PositionDamper
TimeSensor time SFTime |
Worker
Script tick SFTime |
EFFS
ProtoInstance EFFS |
No ROUTE connection found for output from this node. Contains SFNode/MFNode field with indirect access to other nodes. |
<!--
Online at
https://www.web3d.org/x3d/content/examples/Basic/Followers/FollowerPrototypeDeclarationsIndex.html
-->
<!--
Version control at
https://sourceforge.net/p/x3d/code/HEAD/tree/www.web3d.org/x3d/content/examples/Basic/Followers/FollowerPrototypeDeclarations.x3d
-->
<!--
Color legend: X3D terminology
<X3dNode
DEF='idName' field='value'/>
matches XML terminology
<XmlElement
DEF='idName' attribute='value'/>
(Light-blue background: event-based behavior node or statement)
(Grey background inside box: inserted documentation)
(Magenta background: X3D Extensibility)
<ProtoInstance
name='ProtoName'>
<field
name='fieldName'/> </ProtoInstance>
-->
<!-- For additional help information about X3D scenes, please see X3D Tooltips, X3D Resources, and X3D Scene Authoring Hints. -->