cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

We are working to address an issue with subscription email notifications. In the meantime, be sure to check your favorite boards for new topics.

Vuforia Studio and Chalk Tech Tips

Sort by:
How can ThingWorx (external) data be used to update an experience in real-time? For example, if the data does not fall within a specified range, warning messages will be shown automatically.     In ThingWorx, in Thing, create a Service to check the range and to determine if a warning should be displayed or not. In Vuforia Studio, in the Project, in DATA panel, under External Data section, add the Service. Under Configuration section, check all checkboxes related to refresh to call this Service. Use the ServiceInvokeComplete Event to check the value reported by the Service        
View full tip
Often, we need to display some sections, or we required to have a view of a x-section of the model. This is in generally no part of the current functionality but there are some approaches which could be helpful. In this article I want to mention 3 different approaches, which could be used but no one of them is really perfect:   1.) uploading different models -  so we can use an additional models for each cut and then we can change the model if you want to display a cut, it means you can make the one model not visible and the display the second model or vice versa.  I tested with cuts created in Creo Illustrate 5.0 and Creo View 5.0 but it seems that Vuforia Studio could not display them /neither as part of sequence or as static to the current figure:     The only possible  way in this example is to create in Creo an assembly cut /with option cut also on part level  and  then create from there a new .pvz model.  In this case this seems to work fine: :     2.) the second approach is to remove components  step  by step,  so to see the inner components when the outer components are blanked: All different components, which should be displayed or blanked, need to be defined as modelItem where we can set the visible property to true or false Is also possible to blank or display  a list of components where the list is defined in json file. This could be done with JavaScript code. In this case we do not need to define a modelItem widgets.  For more information you can check the post    3.)  The last most powerful option is to use a shader for the model Widget. So for example we can use some kind of clipping functionality of the model where we can set the x min and x max value or ymin and ymax or zmin and zmax value what should be displayed. This will create a clipping effect. So only the geometry which satisfy this criteria will be displayed.     How to achieve a clipping functionality using a shader. 3.1) define a shader - this requires creating a tmlText widget where we can define the shader Code. The code should be inserted into the text property of the tml widget For the clipping along x axis with planes which are parallel to the  YZ plain we need to define the following javascript with GLSL:   <script name="slice_world_based_x" type="x-shader/x-vertex"> attribute vec3 vertexPosition; attribute vec3 vertexNormal; varying vec3 N; varying vec4 vertexCoord; uniform mat4 modelMatrix; uniform mat4 modelViewProjectionMatrix; void main() { vec4 vp = vec4(vertexPosition, 1.0); gl_Position = modelViewProjectionMatrix * vp; vertexCoord = modelMatrix*vp; // the surface normal vector N = vec3(normalize(modelMatrix* vec4(vertexNormal,0.0))); } </script> <script name="slice_world_based_x" type="x-shader/x-fragment"> // this setting is needed for a certain use of properties precision mediump float; // determine varying parameters varying vec3 N; varying vec4 vertexCoord; // determine shader input parameters uniform vec4 surfaceColor; uniform float slicex; uniform float slicewidth; const vec3 lightPos = vec3(1.0, 2.2, 0.5); const vec4 ambientColor = vec4(0.3, 0.3, 0.3, 1.0); void main() { // calc the dot product and clamp based on light position // 0 -> 1 rather than -1 -> 1 // ensure everything is normalized vec3 lightDir = -(normalize(lightPos)); vec3 NN = normalize(N); // calculate the dot product of the light to the vertex normal float dProd = max(0.0, dot(NN, -lightDir)); // calculate current color of vertex, unless it is being clipped... // only geometry with coordinates which satisfy the condition below // will be displayed if ( vertexCoord.x > (slicex + slicewidth/2.0) || vertexCoord.x < (slicex - slicewidth/2.0) ) { discard; } else { // calculate the color based on light-source and shadows on model gl_FragColor = (ambientColor + vec4(dProd)) * surfaceColor; } } </script> Save the tml Text widget .     3.2) You can also define shaders for clipping along the Y and the Z axis. Here you can use the same shader javascript definition but you need to change the shader name and to modify the if  check respectively to the Y or Z coordinate:   <script name="slice_world_based_y" type="x-shader/x-vertex"> ... // calculate current color of vertex, unless it is being clipped... if ( vertexCoord.y > (slicex + slicewidth/2.0) || vertexCoord.y < (slicex - slicewidth/2.0) ) { discard; } else ...   To set the clipping values for different axes and to control it by   sliders we can use some code like this:   $scope.DIR="y"; $scope.slice = function() { var slicexCur = ($scope.view.wdg['slider-1']['value']/100.0)-0.5; var slicewidthCur = ($scope.view.wdg['slider-2']['value']/100.0); $scope.view.wdg['modelx']['shader'] = "slice_world_based_"+$scope.DIR+";slicex f "+ slicexCur + ";slicewidth f " + slicewidthCur; } //////////////////////////////////////////// $scope.$on('$ionicView.afterEnter', function(){ // Anything you can think of $scope.clickY() }); /////////////////////////////////////// $scope.clickX=function() { $scope.view.wdg['toggle-X']['value'] =true $scope.view.wdg['toggle-Y']['value'] =false $scope.view.wdg['toggle-Z']['value'] =false $scope.DIR="x" } $scope.clickY=function() { $scope.view.wdg['toggle-X']['value'] =false $scope.view.wdg['toggle-Y']['value'] =true $scope.view.wdg['toggle-Z']['value'] =false $scope.DIR="y" } $scope.clickZ=function() { $scope.view.wdg['toggle-X']['value'] =false $scope.view.wdg['toggle-Y']['value'] =false $scope.view.wdg['toggle-Z']['value'] =true $scope.DIR="z" } ///////////////////////////////////////   Here the slice() function is called in the slider change event (for the both slider widgets). For better understanding of the functionality you can review the attached Vuforia Studio project Here attached the improved version for HL. It is also approved by dev team.  slice_example.zip https://community.ptc.com/sejnu66972/attachments/sejnu66972/tkb_vuforiatechtips/48/4/slice_example.z... Another version (also for HL) attached here is the example   slice_example_using_ABCD  project – where the dev team demonstrates an efficient way showing how we can define a cutting plane via plane ABCD parameters (refer to  plane geometry equations : geometry https://en.wikipedia.org/wiki/Plane_(geometry)   To cover this functionality the dev team developed some studio extensions that  PTC customers can use instead.   That extensions widgets will handle reflections etc, and I it is recommend to use  those extensions .: https://github.com/steveghee/OCTO_Studio_extensions https://github.com/steveghee/OCTO_effects_extensions  
View full tip
To ensure your Chalk experience is the best, make sure to familiarize yourself with the below best practices.   Initialization Keep movement fluid and slow Forward and backward smooth motion is best to allow device to create mapping Small circles in front of the object are also good Note: Do not rotate your device - keep the device's orientation fixed, moving it parallel to the object of interest and keeping the latter in view during initialization movement Environment It is important for the environment to have a lot of saliency, interesting features, & textures e.g. Stickers, buttons, cables, images/designs, shapes with corners, etc Stationary objects are best for Chalking Reflective, plain colored, or blank surfaces are not good for using Chalk Marks Well-lit areas are best for Chalk performance If an environment is too dark the device's camera will not be able to detect objects External light may be needed if the environment is too dark Either user can toggle the flash on Network/Bandwidth Low bandwidth will result in poor video quality Ensure that you have good bandwidth Chalk Marks Use simple drawings to communicate instructions Circles, lines, & arrows work best Delete Chalk Marks that are no longer needed to reduce clutter Use the pause button to draw on a steady image  
View full tip
Unfortunately, in the Vuforia Studio Documentation there is no complete List with the possible events which could be handled JS. Therefore for the first time this article tries to provide additional Information about known events :   1.) modelLoaded - is not required any more because the UI allow directly to specify this event. ... $rootScope.$on('modelLoaded', function() { //do some code here } ) .... 2.) Step completed example: scope.$on('stepcompleted', function(evt, arg1, arg2, arg3) { var parsedArg3 = JSON.parse(arg3); console.log("stepcompleted stepNumber="+parsedArg3.stepNumber + " nextStep="+parsedArg3.nextStep); $scope.app.stepNumber=parseInt(parsedArg3.stepNumber); $scope.app.nextStep=parseInt(parsedArg3.nextStep); $scope.app.duration=parseFloat(parsedArg3.duration); }); 3.) Event - stepstarted: ... $scope.$on('stepstarted', function(evt, arg1, arg2, arg3) { var parsedArg3 = JSON.parse(arg3); console.warn(arg3); console.log("stepstarted stepNumber="+parsedArg3.stepNumber); $scope.app.stepNumber=parseInt(parsedArg3.stepNumber); $scope.app.nextStep=parseInt(parsedArg3.nextStep); $scope.app.duration=parseFloat(parsedArg3.duration); }); ... Please, pay attention that on some platforms will not provide complete information  in stepstarted. So, In this case the complete info is available in 'stepcompleted' – the best is to test it.   4.) after entering in  a view in studio (e.g. Home ...):   ... $scope.$on('$ionicView.afterEnter', function() {$scope.populateModelList(); }); ... 5.) click/tap event on the current panel: ... $rootScope.$on('click', function() { tapCount++;console.log("click event called");} ); ... or  with coordinates ... document.addEventListener('click', function(event) {console.log("click() 1 called"); $scope.lastClick = { x: event.pageX, y: event.pageY}; }); ... you can also see this topic.   6.) New step  -example: ... $scope.$on('newStep', function(evt,arg) { var getStepRegex = /\((\d*)\//; console.log(arg); console.log( getStepRegex.exec(arg)[1]); //check what it prints to the console - the step number }); ...    7.) Here is also  a more advance construct- it defines a userpick event e.g. for all models widgets: angular.forEach($element.find('twx-dt-model'), function(value, key) { // search all twx-td-model's -> means all model widgets angular.element(value).scope().$on('userpick',function(event,target,parent,edata) { //for each model widget will set a userpick listener console.log('edata');console.warn(edata); console.log("JSON.parse(edata)");console.warn(JSON.parse(edata)); var pathid = JSON.parse(edata).occurrence; $scope.currentSelection = target + "-" + pathid; // this is the current selection - the selected component occurence // you can use it for example as shown below // try{ //tml3dRenderer.GetObject($scope.currentSelection).GetWidget().ApplyOccludeOpacity(OCLUDE_VAL,OPACITY_VAL); //} catch (e1234) {$scope.view.wdg['3DLabel-4']['text']= "e 1234exception in GetObject.GetWidget..."; } // } ) //end of the userpick defintion } ) //end of for each funciton  8.) tracking event:   ... $scope.$on('trackingacquired', function (evt,arg) { // alert('didStartTracking'); // this is not really needed $scope.message = parseInt($scope.app.params["currentStep"]); $scope.$apply(); }); $scope.$on('trackinglost', function (evt,arg) { // alert('didFinishTracking'); $scope.message = "Scan the ThingCode with your camera."; $scope.$apply(); }); ....   9.) popover event:     // var my_tmp = '<ion-popover-view><ion-header-bar> <h1 class="title">My Popover Title</h1> </ion-header-bar> <ion-content> My message here! </ion-content></ion-popoverview>'; $scope.popover= $ionicPopover.fromTemplate(my_tmp, { scope: $scope }); $ionicPopover.fromTemplateUrl('my-popover.html', { scope: $scope }).then(function(popover) { $scope.popover= popover; }); $scope.openPopover= function($event) { $scope.popover.show($event); }; $scope.closePopover= function() { $scope.popover.hide(); } //////////////destroy popover $scope.$on('$destroy', function() { $scope.popover.remove(); }); /////// hide popover $scope.$on('popover.hidden', function() { // your hide action.. }); // on remove popover $scope.$on('popover.removed', function() { // your remove action }); }); 10) watch event -watches are created using the $scope.$watch() function. When you register a watch you pass two functions as parameters to the $watch() function: 1)A value function 2)A listener function    When the value returned by function 1.) changes - this lead to execution of the funciton 2.) Example:   ... $scope.$watch(function(scope) { return $scope.view.wdg['label-1']['text'] }, // watches if change for the the text of label-1 //when changes then play a step for model-1 function() { console.log($scope.view.wdg["model-1"]); $scope.view.wdg["model-1"].svc.play; } ); ...   11.) Camera tracking - make sense only on mobile device- no sense for preview mode!   //// define tracingEvent only on end device tml3dRenderer.setupTrackingEventsCommand (function(target,eyepos,eyedir,eyeup) { // $scope.view.wdg['3DLabel-1']['text']="eyepos=("+eyepos[0].toFixed(2)+","+eyepos[1].toFixed(2)+","+eyepos[2].toFixed(2)+")"; $scope.app.params['target']=target; $scope.app.params['eyepos']="eyepos=("+eyepos[0].toFixed(2)+","+eyepos[1].toFixed(2)+","+eyepos[2].toFixed(2)+")"; $scope.app.params['eyedir']="eyedir=("+eyedir[0].toFixed(2)+","+eyedir[1].toFixed(2)+","+eyedir[2].toFixed(2)+")"; $scope.app.params['eyeup'] ="eyeup =("+ eyeup[0].toFixed(2)+","+ eyeup[1].toFixed(2)+","+ eyeup[2].toFixed(2)+")"; ///////////////////// },undefined); //// define tracingEvent only on end device } //end device   12.) There is also a sequenceloaded event, which is useful if you have a model with multiple sequences defined, and you are switching sequences dynamically in the experience.   $scope.$on("sequenceloaded", function (evt, arg) { console.log("sequence loaded, starting play"); $scope.setWidgetProp("loading","visible",false); $scope.app.fn.triggerWidgetService("model-1","playAll"); }); In this point is  here a good feedback comming from advance user (expert) : If you grep for "$emit" through a project folder, you can turn up the following event names: valueacquired (bar code scanner) usercanceled (bar code scanner) tracking modelloadfailed sequenceloaded newStep playstarted sequenceacknowledge playstopped sequencereset onReset If you grep for "$on(", you can find some additional ones: trackingacquired trackinglost modelLoaded click app-fn-navigate app-fn-show-modal app-fn-hide-modal $ionicView.afterEnter $stateChangeStart loaded3DObj loadedSeqErr loadedSeq $destroy select3DObj move3DObj loadError3DObj readyForZoom3DObj serviceinvoke stepstarted stepcompleted twx-entity twx-service-input twx-service-name This is a  good point and it seems that this list contains the most of the possible events.   Events Handling Feedbacks from EXTERNAL DATA  services  Such event is    the twx-service complete event. This event is called when we call a service registered in the external data and the service is completed. Here an example (also mention in the post😞 Here in the example in the external data the service LoadJSON was added.       ////////////////////////////////////////////////////////////// $scope.GetJsonFromTwxRepository = function(path) { $scope.$applyAsync(function() { $rootScope.$broadcast('app.mdl.CAD-Files-Repository.svc.LoadJSON', {"path":path} );} ,500 ); $scope.app.speak("after call of GetJsonFromTwxRepository") //in the modelloaded listener register // LoadJSON-complete event -> to laod the data into session rootScope.$on('modelLoaded', function() { //// $scope.$root.$on('LoadJSON-complete', function(event, args) { console.log("LoadJSON-complete event"); $scope.COMP_LOCs=args.data console.log(JSON.stringify( $scope.COMP_LOCs)) }); /// });   So the code above shows how to call from JavaScript the service added to the external data. This service should return the called JsonObject. The call is asynchronously so that when  thingworx  will come back the listener 'LoadJSON-complete' will be called and here will print the content of the JsonObject to the console. Here the listener is registered inside the modelload event (this is event is coming late – so to be on the save side that everything is already initialized) This is generally that you for any Thingworx services added to the External data <your_twx_service_name>-complete  the arg.data contains then the data which should be returned by the method.
View full tip
  This example briefly describes how you can use the Step names that you used in Creo Illustrate sequence definitions to drive a corresponding step instruction/description in your experience. This is an unsupported, preliminary solution - R&D is working on a better, final solution. But as long as this is not available, you can use this one for PoC and demo purposes. To setup the scene: Here is what I meant with Step names that you used in Creo Illustrate: Now in Thingworx Studio you want to have the following result: The text is rendered with a simple Label widget. You'll have to remember the ID of this widget for the following javascript tweak. Add the following text to the Javascript section of your View: var labelId = "label-1"; // ID of the Label widget that displays the Step progress and description  text // this $on event handler switches the label based on the the sequence definition // the arg variable is of the following form: (<step #>/<total step #) <step name> $scope.$on('newStep', function(evt, arg) {   $scope.setWidgetProp( labelId, "text", arg); // get the currentStep from the arg }); Now you only need to provide the correct initial value in the Label widget text property and add control widgets (Buttons, Playback) to drive your animation and you're done. Easy!    
View full tip
Your company might have a css that represents the corporate identity - or you may have other sources of reusable css styles that you want to include with minimal effort. Here is what you have to do to use corporate css files to drive the look and feel of your experiences: Add the corporate css file (e.g. company.css) to your resources In Application styles add the following at the beginning (before any other css style entry: @import url(#{$resources}/Uploaded/company.css);     With the following content in company.css: And this label definition:   Produces this outcome (you see it in the editor as well as in the preview):   Gotcha!    
View full tip
In Vuforia studio the best way to interact with 3d model components is to define explicit 3d modelitems (widget modelItem). So this will be an easy way to access the componets and to change their properties e.g. setting of the color  e.g.: $scope.setWidgetProp("modelItem-1", "color",  "rgba(128,0,0,1)");   This will  change the modelItem-1 property color to brown – and will display the component which is specified by this modelItem with a  brown color. Another way to do this in javaScript is something like :   $scope.view.wdg['modelItem-1']['color'] = "rgba(128,0,0, 1);";//brown $scope.view.wdg['modelItem-1']['opacity'] = 0.5;//set transparency to 0.5 //or for the same $scope.setWidgetProp("modelItem-1", "color", "rgba(128,0,0,1);"); //brown $scope.setWidgetProp("modelItem-1", "opacity", 0.5); //set transparency to 0.5   But in some cases during the project development it  could  be helpful when we are  able to manipulate the components or request information about them without defining of explicit modelItem widgets. For example if we want to select a component to see some information about the component and change the color of it:   var PICK_COLOR = "rgba(255,0,0,1)"; ... $timeout( //timeout block 1 function() { //timeout function 1 angular.forEach( //==== for each 3d model block // this will call the function below for each 3d model $element.find('twx-dt-model'), function(value, key) { //for each 3d model block function //===================================================================================== angular.element(value).scope().$on('userpick',function(event,target,parent,edata) { // start the $on() listener 'userpick' + function definition //================================================================================= var pathid = JSON.parse(edata).occurrence; $scope.currentSelection = target + "-" + pathid; // create a component selection e.g. "model-1-/0/0/3/2" console.log("twx.app.isPreview() ="+twx.app.isPreview() ); //print an info if is called in preview mode and could be checked if required try{tml3dRenderer.setColor($scope.currentSelection, PICK_COLOR);} catch (ex) {console.warn("Exception 1 in tml3dRenderer.setColor()=>"+ex);} //will set the color of the selected component } //end of mobile device modelItemsList.push($scope.currentSelection); } //end is in array //================================================================================= }); // finish the $on() listener 'userpick' + function definition } //finish for each 3d model block function ); // finish for each 3d model block //================================================================================= } ,50); // finishtimeout block 1 and function   If  we use  PICK_COLOR  = "rgba(255,0,0,0)"; It means that this color (red) is set for a selected component. Here the one additional detail is the last argument - which have a value of 0. Means alpha channel =0 - or full transparence. On the most mobile devices it will hide the selected component, but this is not supported techniques and we have to use always color with alpha channel >0. / transparent but still visible/   Calling of the tml3dRenderer.setColor(…, undefined); will set the component color back to default - example:   tml3dRenderer.setColor(‘model-1-/0/0/3/2’, undefined);    Another important point is that when we know the model name and know the component ids, in this case we can also set the color or hide components without explicit definition of model items. For example for a particular model we have prepared  a json file (*):     { "/0/0/2" :"rgba(255,0,0,1);", "/0/0/0" :"rgba(128,0,0,1);", "/0/0/5" :"rgba(128,0,128,1);", "/0/0/3/0":"rgba(0,255,0,1);", "/0/0/6" :"rgba(255,200,0,1);", "/0/0/3/1":"rgba(0,0,0,0.2);", "/0/0/7/0":"rgba(0,0,0,0.2);", "/0/0/7/1":"rgba(0,0,0,0.2);" }   The model to which this json file was created is placed in Vuforia Studio as model widget with name=model-1  We can then read this json file (from prject->src\phone\resource\Uploaded folder) with some javaScript construct like (below) and set the color property of the components (also change the transparence - for the components with alpha channel =0.2)  Here an example (*):   //======================================================== // reading a json file with component setting for the components //======================================================== $scope.setCompProps=function() { var FILES_MODEL_COMP = { 'model-1':'comp_info.json' }; $scope.compJSON_Data = new Array(); angular.forEach(FILES_MODEL_COMP, function(jsonFile, target) { console.log("angular.forEach jsonFile = "+jsonFile + ", target="+target); $http.get('app/resources/Uploaded/' + jsonFile).success(function(data, status, headers, config) { $scope.compJSON_Data[target]=data; // in this case is $scope.compJSON_Data['model-1']= of the json structure file here the content'comp_info.json'; angular.forEach(data , function(color, path_id){ console.log("target="+target+" --> color = "+color + ",path_id="+path_id); tml3dRenderer.setColor(target+'-'+path_id, color); });//end for each function }) .error(function(data, status, headers, config) {console.log("calling in foreach 1 failed"); }); }); };     So when we start for this particular model the test code it will change the display of the model according to the setting of the comp_info.json  file:     The code above is more than intended for setting colors and transparency  . According a recommendation from development for hiding of components is better to use  the hidden property:   tml3dRenderer.setProperties($scope.currentSelection, { hidden:true } );   The sample  code below  ( more simplified) is  for the case that we want to blank a component by click on it:   angular.forEach($element.find('twx-dt-model'), function(value, key) { // search all twx-td-model's -> means all model widgets angular.element(value).scope().$on('userpick',function(event,target,parent,edata) { //for each model widget will set a userpick listener try{ console.log('edata');console.warn(edata); console.log("JSON.parse(edata)");console.warn(JSON.parse(edata)); var pathid = JSON.parse(edata).occurrence; $scope.currentSelection = target + "-" + pathid; console.log("=>>"+$scope.currentSelection); } catch (ea) {console.error("not twx-model is clicked but still fired")} try{ // here below the change recommended from R&D tml3dRenderer.setProperties($scope.currentSelection, { hidden:true } ); } catch (e1234) {console.error( "e="+e1234); }   Here tested the code on the HoloLens 1.0 device:     When we have a color definiton  with  opacity -> the alpha channel set here e.g. to 0.1 /  and the defined color should be changed later :   var PICK_COLOR_OPACITY1 = "rgba(,,,0.1)";   to change the rgba expression by setting another value of transparency you can use some construct like this:   var PICK_COLOR_OPACITY1 = "rgba(,,,0.1)"; var OPACITY_VAL=0.3; var PICK_COLOR_OPACITY2= PICK_COLOR_OPACITY1.replace( "0.1)",OPACITY_VAL+")");   The JavaScript code above  will set transperancy value of  0.3 (replacing the 0.1 by 0.3) But for the case that we have in a json file a defintion of color with alpha chanel =0  :     ... "/0/0/3/1":"rgba(0,0,0,0.0);", ...   In this case we can  modify (recommended)  the code to check the value of the alpha channel and if it is ==0 to set  the "hidden" property  - example (*) :   ... //======================================================== // reading a json file with component setting for the components //======================================================== $scope.setCompProps=function() { var FILES_MODEL_COMP = { 'model-1':'comp_info.json' }; $scope.compJSON_Data = new Array(); angular.forEach(FILES_MODEL_COMP, function(jsonFile, target) { console.log("angular.forEach jsonFile = "+jsonFile + ", target="+target); $http.get('app/resources/Uploaded/' + jsonFile).success(function(data, status, headers, config) { $scope.compJSON_Data[target]=data; // in this case is $scope.compJSON_Data['model-1']= of the json structure file here the content'comp_info.json'; //because R&D statement to use hidde property need to check of alpha chanel ==0 angular.forEach(data , function(color, path_id){ console.log("target="+target+" --> color = "+color + ",path_id="+path_id); var start_alpha = color.lastIndexOf(","); var end_alpha = color.lastIndexOf(")"); var alpha_str = color.substring(start_alpha+1, end_alpha); var num = Number(alpha_str); if ( (isNaN(num )) || (num <= 0.0) ) {//set color properly to alpha channel 1.0 var new_color= color.substring(0,start_alpha+1)+"1.0"+ color.substring(end_alpha,color.length) tml3dRenderer.setColor(target+'-'+path_id, new_color); tml3dRenderer.setProperties(target+'-'+path_id, { hidden:true } ); } else { // color unchanged tml3dRenderer.setColor(target+'-'+path_id, color); } });//end for each function }) .error(function(data, status, headers, config) {console.log("calling in foreach 1 failed"); }); }); }; ///////////// ...   The example above will set to the component the correct values of the color but with alpha channel 1.0 and will interpret the original alpha value from the file as setting of the hidden property to true.  Does this make sense? Yes if we later set the hidden property to false then the color setting will be applied according to the definition from  the json file
View full tip
This is the second Javascript quark in the series: it can be used to fade a widget out. You can find the first quark here.   Here's the code to copy & paste to your Home.js:   $scope.fadeOut = function(widget, time, interval) { let w = (widget.opacity !== undefined ? widget : $scope.view.wdg[widget]); if (time <= 0 || interval <= 0 || w.opacity === undefined) { throw "Cannot fade this widget"; } let steps = Math.floor(time / interval); let opDelta = w.opacity / steps; return $interval(() => w.opacity = (opDelta < w.opacity) ? (w.opacity - opDelta) : 0, interval, steps); } This quark will make the widget fade out from its current opacity to 0 in time milliseconds, uniformly decrementing opacity at every interval .   Invoke the function like this:   fadeOut(widget, time, interval);   where widget is either the id of the widget (e.g. modelItem-1) or the widget itself (e.g. $scope.view.wdg['modelItem-1']), time represent the total time it takes to fade the widget out from its current opacity, and interval represents the amount of time between each opacity change.   Here's an example:   fadeOut('modelItem-1', 2000, 50); This example fades the model item out by bringing its current opacity to zero after 2 seconds with an opacity change every 50 ms.   Comments and suggestions are welcome.   -Alessio    
View full tip
This is the third JavaScript quark in the series: it can be used to change a widget color by cycling through a given array of colors. You can find the second quark here.   Here's the code to copy & paste to your Home.js:   $scope.cycleColors = function(widget, colors, time, interval) {   let w = (widget.color !== undefined ? widget : $scope.view.wdg[widget]);   if (!w || w.color === undefined) { throw "Cannot color-cycle this widget"; }   let originalColor = w.color;   w.color = colors[0];   w.visible = true;   w.opacity = 1;    let nSteps = Math.ceil(Math.floor(time/interval) / colors.length) * colors.length;   return $interval(iterationCount => w.color = iterationCount === nSteps ? originalColor : colors[iterationCount % colors.length], interval, nSteps); } This JavaScript quark will make the widget color cycle through the colors provided in the colors array. The effect will last time milliseconds, and each color change will happen every interval milliseconds.   Invoke the function like this:   cycleColors(widget, colors, time, interval);   where widget is either the id of the widget (e.g. modelItem-1) or the widget itself (e.g. $scope.view.wdg['modelItem-1']), colors represents an array of colors (e.g. ["rgba(200,0,0,1)", "rgba(0,0,200,1)"]), time represents the total time in milliseconds it takes to execute this effect, and interval represents the amount of time in milliseconds between each color change.   Here's an example:   cycleColors("modelItem-1", ["rgba(200,0,0,1)", "rgba(0,200,0,1)", "rgba(0,0,200,1)"], 2000, 50); This example cycles the model item color through red, green and blue; the effect will last for 2 seconds with a color change every 50 ms.   Comments and suggestions are welcome.   -Alessio  
View full tip
At the frist sight the  issue , may be , seems to be more related to thingworx or navigate, but this is often a question which is related to models  used in Studio and customers want to have some tools to view such models outside Vuforia Stuido and Vuforia View . Another important point is that Vuforia Studio Preview,  Navigate Thingview  and Creo View WebGL Toolkit use /are based on  the same thingview library.   The official statement of PTC here is that thingview widget, which is part from the Navigate extension is not supported for customized mashups and correct work is guaranteed  only as part of the navigate functionality. Therefore, there is no documentation provided for the customization of this widget and no technical support cases will be handled on address of related issues. Also the geometry file formats  supported by thingview are mainly the files supported by the Creo View application. All other file formats (which are not availalbe in the open dialog box of Creo View) are not supported -> e.g. glTF format. Of course, this can change in a future versions ->  therefore, please, check for future releases always the "What's new" docs. Actually the thingview allows  opening of some simple glTF files. But this is not working for every glTF file. Mostly there is a problem when we have geometry with high complexity.  … Additional I want to pont that not supported does not mean is not allowed. So therefore, I want to provide here some Info in case that customers want to customize the thingview widgets at their own risk. (no bug fixing and no compatibility guaranteed for future Releases)   In this post I will only introduce  the concept of such mashup's/view's and then in further posts will consider the different details for the different  suppoints in the picture below.      In the picture above, we have an example for customized mashup where we have a different areas for the different functionality. The mashup displayed in design /edit mode should looks like:     The mashup contains the following main areas(marked in the picture with a callouts numbers 😞   1.) Selector for the models. This is a list element widget which provides the possibility for the  selection of a particular model. The list  here is based on an Infotable returned by a service. Here is an example how to implement such service:     For simplification reason the service contains here only 2 rows. Here is an example how to implement such service (javaScript code) :     var data = [ { "FileName": "Machine-complete-CV.PVZ", "repository_link": "https://mrerot7o.studio-trial.thingworx.io:8443/Thingworx/FileRepositories/CAD-Files-Repository/CADFiles/Machine-complete-CV.PVZ", "json_bom": "/CADFiles/json_lists/Machine-complete-CV.PVZ-bomlist.json", "json_viewable_list": "/CADFiles/json_lists/Machine-complete-CV.PVZ-viewablelist.json", "json_viewable_stepList": "/CADFiles/json_lists/Machine-complete-CV.PVZ-viewableSteplist.json" }, { "FileName": "worldcar-brake-multi-figure.pvz", "repository_link": "https://mrerot7o.studio-trial.thingworx.io:8443/Thingworx/FileRepositories/CAD-Files-Repository/CADFiles/worldcar-brake-multi-figure.pvz", "json_bom": "/CADFiles/json_lists/worldcar-brake-multi-figure.pvz-bomlist.json", "json_viewable_list": "/CADFiles/json_lists/worldcar-brake-multi-figure.pvz-viewablelist.json", "json_viewable_stepList": "/CADFiles/json_lists/worldcar-brake-multi-figure.pvz-viewableSteplist.json" } ]; var result = DataShapes.files_repository_source_shape.CreateValues(); for(var i =0;i<data.length;i++) { result.AddRow(data[i]); }   The return type of the service is an InfoTable . For the defintion of the InfoTable we need a DataShape for the used fields definitions:     The list Widget ( callout 1.)  in the picture) has a binding to the thingview data.  When we select in the list widget a model -> this will call  the services: {(getViewableSteplist_arg_path(), getViewableSteplist_arg_path_viewablename()  and GetBomStruct_arg_path() }  of the  CAD-Files-Repository (Repository Thing - means  a thing which uses the template FileRepository)  -> and will pass the arguments for the json files paths for bom , viewables and StepList .     The effect is that- when we select a model in the listWidget -> this will update the mashup and will display only data related to this model.  All models and Json Files in this example  are saved in the Repository "CAD-Files-Repository"     To upload data to the repository we can use the File Upload widget. To display (for testing)  the data we can use the GetDirectory() and GetFileListingWithLinks() services of the repositroy thing. Below is an example for tool mashup which could be used as a tool to upload and display the data in the repository -as shown in the  picture above:     2.) Model tree area (callout 2.). This will display the model tree of the assembly components. It requires a service returning an InfoTable.  - here an example the service {Things["CAD-Files-Repository"]. GetBomStruct_arg_path(the_json_path) }  is called and returns the folloiwng   output:       For the creation of the infoTable I used  here a json file. In this example the the information about the viewalbes and steps  was extracted from  PTC sample assemble worldcar-brake-multi-figure.pvz   to the file  "worldcar-brake-multi-figure.pvz-viewableSteplist.json" (attached to this post). How to generate such file with Creo View WebGL toolkit is described in the community post (How to extract the components with properties from a pvz file)   The step how to create an InfoTable  from a  Json will is handled in an addtional post (Service for creating of Bom - and Viewable Lists from json files)   For the  displays of the data as an assembly  tree the tree widget has the following settings:     3.) List area - the functionality in this area uses  the same services as in point 2.)  but it  displays the components bom in a Thingworx Grid widget.  This will list the Bom as list of all components  (uses also the service {Things["CAD-Files-Repository"]. GetBomStruct_arg_path(the_json_path) } )     In the mashup preview it will looks like:     4.) Area for the selection of a viewable /  viewable = Creo Illustrate Figures ( callout 3  in the  the overview picture)     To  display the viewables correctly in thingview we require to have a service/data which is based on InfoTable with specific field definition (specific field name + type  is important that it works)       We can bind the All Data of the service  (here : {Things["CAD-Files-Repository"]. getViewableList_arg_path(the_json_path) } ) to the Views property of the thingview widget. Depending on the values of the fileds HasAnimation and HasSequnece the buttons for playing of sequences and animation are shown or blanked (set the Visible property to true or false)      How to define the service used for this point (returns InfoTable with list of the viewables) is described in the post  (Service for creating of Bom - and Viewable Lists from json files)   5.) Area for the display of the  sequence steps > data grid widget-> it displays data  only if the current viewable is a sequence.  Here  below an example for the results of the service execution (getviewableStepList )   for a Json files related to  models which have 1 (worldcar-brake-multi-figure.pvz)  respectively  2 (Machine-complete-CV.pvz) sequences. In the attached sample file  you can find  the  json file:  (worldcar-brake-multi-figure.pvz-viewableSteplist.json)       Here is an example of the mashup dipslay where we can see a Sequnece containing viewables     We can see the same mashup in design/edit mode (below). We can bind the All Data of the service  (here : {Things["CAD-Files-Repository"]. getViewableSteplist__arg_path_viewablename(the_json_path, the_viewablename) } ) to the Data property of the grid  widget. How to extract  a json file from the pvz model (e.g. worldcar-brake-multi-figure.pvz-viewableSteplist.json) and how to define the service for lnfoTable generation  e.g. getViewableSteplist_arg_path_viewablename -> this is shown in the post (Extracting the viewables and the seqnece steps information from a .pvz file for the usage in TWX).      The display of the Step List  is here provided only as info. Because there  was not possible to set the current /selected dataset in the grid widget. Therefore I used  here an additional List widget (callOut 6 ) which helps to manage this problem   6.) The area of the List widget is an area  which should be made invisible. It is used only to allow the setting of the selection in the grid element. We can bind the All Data of the service  (here : {Things["CAD-Files-Repository"].getViewableSteplist__arg_path_viewablename(the_json_path, the_viewablename) } ) to the Data property of the List  widget (callOut 6). The list element ( 6.) could be blanked because it is only used to set the selection of the  gird table (default  functionality of the Data selection )   How to extract  a json file from the pvz model (e.g. worldcar-brake-multi-figure.pvz-viewableSteplist.json) and to define the service for it  e.g. getViewableSteplist_arg_path_viewablename - is shown in the post(Extracting the viewables and the seqnece steps information from a .pvz file for the usage in TWX).   7.) This is the area with the panel of the Thingview (Thingview is a thingworx  extension). The thingview widget is part of the windchill navigate module. If the extension is installed , we can check this in the Extension manager:     In the package details we can see  that the thingview widget is installed on this thingworx instance  
View full tip
Currently, we do not recommend using Vuforia Studio with Chrome 106.0.5249.91 or later and Microsoft Edge 106.0.1370.37 due to a major issue with Chromium; Google has been made aware of the issue. Until it is resolved, we recommend using older versions of Chrome or Microsoft Edge.   Vuforia Studio The Wayfinder widget is now out of beta and full access is available. Improvements to the Wayfinder widget include: A pop-up with information about the Wayfinder widget appears when the widget is added to an experience A new Looping property is available that returns a user to the first Waypoint in the array once the last Waypoint is reached Improved ribbon density Improved property names Default gaze vector is now 90 degrees from the surface that the Waypoint is mated to Improved text label design Vuforia View Target acquisition effect is available on all mobile platforms NOTE: The model recognition for Advanced Model Targets will be visualized by a snapping effect in the experience.  HoloLens 2: Wayfinder and Waypoints are now available for 3D eyewear experiences Experience Service There are no new features or updates for the 9.7.1 version of the Experience Service
View full tip
Vuforia Studio 2D Rendering Updated from AngularJS to LitElement The 2D rendering in Vuforia Studio has been updated to use LitElement instead of AngularJS. Vuforia View RealWear RealWear has announced that RealWear HMT-1 devices are at end-of-life, and will no longer receive firmware or security updates beyond v12.6. As a result, we will be unable to fully support HMT-1 and HMT-1Z1 devices beginning in the upcoming 9.21.0 release. We encourage you to upgrade to RealWear’s Navigator series for continued device support from PTC. For more information, see RealWear’s RealWear HMT-1 and HMT-1Z1 End of Security Update support notice and Firmware Update and Support Policy. Bug Fixes See Bug Fixes for additional information on bugs resolved in this release
View full tip
You can rename a project to avoid overwriting an existing published project with the same name on your Experience Service. To Rename your project, open the project you want to rename and click on the project name in the header bar; the field will become editable. For additional information, see Rename a Project  Here are a few things you need to consider when renaming a project: Renaming an already published project creates a duplicate of the project that is unpublished; it does not rename the already published project on the Experience Service To avoid having multiple copies of the same project on your Experience Service, unpublish the original project before renaming it and publishing it. Once you rename an already published project, and then publish the renamed project, a new QR code is created (different from the originally published project's QR code)
View full tip
Vuforia Studio Known Issue: Unable to Upload Files to Vuforia Studio in Chrome for Mac OS There is currently a known issue in Chrome for Mac where users are unable to upload files to Vuforia Studio when using Chrome 122.0.0.0 and 123.0.0.0. If you are using either of the aforementioned versions of Chrome for Mac, please update to Chrome 123.0.6312.10 to resolve the issue. According to Google, this issue should be resolved in Chrome 124.0.0.0. For more information, see Google’s IssueTracker. New Project Overwrite Message When Publishing A new message appears when a user publishes a project that has the same name as an existing published project on the same Experience Service. Project Name Can Now Be Updated from the Header Bar within a Project Users can now rename a project by clicking on the project name in the header bar from within a project. Image Targets Now Generated at Runtime Image Targets are now generated at runtime, and no longer at design time. Note: If you’re using Vuforia View 9.16.0 or above, all existing projects and new projects should work as expected as this change is backwards compatible. However, experiences that contain an Image Target and have been created with Vuforia Studio 9.19.0 and above will not work properly when consumed with Vuforia View 9.15.0 and below. Performance Improvement to Uploading a CAD Model .glb files no longer appear under Resources to help improve performance when uploading a CAD file. Bug Fixes See Bug Fixes for additional information on bugs resolved in this release
View full tip
Vuforia Studio Project Name Now Available in Metadata Project name is now accessible through scripting in Home.js. Vuforia View Support for Android 14 OS Android 14 OS is now supported. Bug Fixes See Bug Fixes for additional information on bugs resolved in this release
View full tip
Vuforia Studio There were no new features or updates for the 9.17.0 version of Vuforia Studio Vuforia View HoloLens: Dynamic bounding box information is now available at runtime iOS: iOS/iPadOS 17 is now supported iOS/iPadOS 15 is no longer supported Experience Service Ability to disable publishing experiences for offline viewing Note: If your Experience Service is hosted by PTC Cloud Services, open a Technical Support case requesting to update the configuration Bug Fixes See Bug Fixes for additional information on bugs resolved in this release
View full tip
Vuforia Studio Improved messaging for Advanced Model Target status when publishing a project Vuforia View A new Show Tracking Status option is available from the menu within an experience. Possible statuses include: TRACKING IS STABLE TRACKING IS UNSTABLE REDUCE MOTION IMPROVE LIGHTING OBJECT OUT OF VIEW Experience Service (on-premises) There were no new features or updates for the 9.15.0 version of the Experience Service. Bug Fixes See Bug Fixes for additional information on bugs resolved in this release
View full tip
Vuforia Studio Bounding box and location information is now available in CAD metadata New RealWear Nav 520 option available in the custom canvas size drop-down list on the 2D canvas JavaScript properties now documented for all widgets Vuforia View Vuforia View is no longer supported on the following devices: Surface Pro 7 Surface Pro 6 Surface Pro 5th Gen (2017) Surface Pro 4 Surface Book Surface Go Surface Go2 Vuzix M400 Smart Glasses You may still be able to use Vuforia View to consume published experiences on these devices, but Technical Support will no longer be available. You should also expect that Vuforia View may stop working correctly on these devices after September 2023. Then, at the end of the year (2023), the following will happen for Windows and Vuzix devices: Vuforia View will be removed from the Windows Store. Vuforia View will be removed from Vuzix App Store. No updated versions of Vuforia View for Windows will be available on the PTC Software Downloads site; only older preexisting versions will remain. Experience Service There were no new features or updates for the 9.14.0 version of the Experience Service. Bug fixes See Bug Fixes for additional information on bugs resolved in this release
View full tip
Vuforia Studio New and improved Model Target widget allows more advanced configurations of Model Targets  including: Automatic coloring of Model Targets Simplification when a model is too complex (for Advanced Views) Ability to create multiple Advanced Model Targets You can now use a command prompt shortcut to configure Vuforia Studio to run over HTTPS Vuforia View RealWear Navigator 520 devices are now supported Experience Service (On-premises) Access to Vuforia Cloud Services to generate Advanced Model Targets is now available for on-premises installations of the Experience Service. For more information, see Request Advanced Model Target Generation. For more information about installing and deploying an Experience Service on-premises, see the Experience Service Help Center. Bug fixes See Bug Fixes for additional information on bugs resolved in this release
View full tip
As part of the Vuforia Studio 9.13.0 release, a new way to create and configure model targets is now available!    The updated Model Target widget allows users more configuration options within Vuforia Studio to ensure optimal tracking of their models. Advanced configuration options include:   Automatic coloring of Model Targets Simplification when model is too complex (Advanced Views only) Multiple Advanced Guide Views For additional information on these new options, see our Configure a Model Target Help Center topic.
View full tip
Vuforia Studio (Windows only) The ssl-settings.json file has been moved to the ProgramData directory for streamlined SCCM deployment. Note: This only applies to Vuforia Studio run over HTTPS. A new shortcut to configure HTTPS locally for Vuforia Studio is now available. For more information, see Vuforia Studio run over HTTPS. Vuforia View An updated version of Vuforia View was not released for 9.12.0. Experience Service There are no new features or updates for the 9.12.0 version of the Experience Service. Bug fixes See Bug Fixes for additional information on bugs resolved in this release
View full tip