Skip to main content
1-Visitor
June 8, 2020
Solved

Simulate Fluid Flow

  • June 8, 2020
  • 2 replies
  • 8642 views

Hello,

 

is it possible to represent a fluid flow just like it shown in the video?

How can i achieve that? With JS or JS and the TML-Widget?

 

Thanks you for every tip.

Best answer by RolandRaytchev

Hi @DenGrz ,

 

today I tested the issue   further with a pipe in z-direction and see there -  then the " shader did not work. And this seems to be a problem of the shader implementation it self. Because when I rotate the pipe in the Y direction then was working fine. It works only flat in the x,y plane. So , this required to check the shader implementation more detailed. The solution is some kind of rotation of the  shader along the Y -axis:

 

 

So changed the shader defintion (for the red pipes) to this - added  addtional argument for Z-roation:

<script name="texture_test1" type="x-shader/x-fragment">

 precision mediump float;
uniform sampler2D Texture0;
uniform float lightscale;// light intensity
uniform float scale;
uniform float moveX;
uniform float moveY;
uniform float rotZ; //
#define PI 3.14159265359
 // determine varying parameters
 varying vec3 N;
 varying vec4 vertexCoord;
 // determine shader input parameters
 uniform vec4 surfaceColor;
 
//light positions from pont to zerro 
 const vec3 lightPos = vec3(3.0, 3.0,1.0);//light postion see the pulb in model
 const vec4 ambientColor = vec4(0.5, 0.5, 0.5, 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 the color based on light-source and shadows on model
	 vec2 TexCoord = vec2( 0.0,0.0);
 // here the rotation along the Y -axis
 // affects only the X axis 
 float ang= rotZ*PI/180.0;
 TexCoord.x= scale*( cos(ang)*vertexCoord.x + sin(ang)*vertexCoord.z);
 TexCoord.y = scale*vertexCoord.y;
 TexCoord.x=TexCoord.x+moveX;
 TexCoord.y=TexCoord.y+moveY;
 
 vec4 color = texture2D(Texture0, TexCoord) ;

 gl_FragColor = (ambientColor*lightscale + vec4(dProd)) *color ;// surfaceColor;
 }
 }
</script>

<script name="texture_test1" 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>

 

 And here the usage in the code:

 

...
$scope.app.shaderString1="texture_test1;scale f .5;moveX f 0;moveY f 0;rotZ f 90.0;lightscale f 1.0";
...
//in init function
 for(var j=6;j<8;j++){
 $scope.view.wdg['modelItem-'+j]['texture'] = "app/resources/Uploaded/waterred.jpg?name=Texture0&edge=repeat"; 
 $scope.setWidgetProp('modelItem-'+j, 'shader', $scope.app.shaderString1);}
 $scope.$applyAsync()
...
//========================================================
$scope.app.setShaderNew1= function(widgetName,scalepar,xDir,yDir,zRot,delay,duration)
{
var calldelay =3000; //3 seconds
var callduration=10000;//10secs
var jumpInterval=5;
 
 if(delay !=undefined) calldelay = delay;
 if(duration !=undefined) callduration = duration;
 
$timeout( () => {
 
 $interval(function() { 
 
 if($scope.val >500) $scope.val =0
 else $scope.val +=1
 
 var scale= parseFloat(scalepar);
 var moveX= $scope.val/500*xDir;
 var moveY= $scope.val/500*yDir;
 var rotZ= zRot;
 var transp= 0.75+0.25*(Math.sin(12.0*Math.PI*$scope.val/500));//6 waves

 
 $scope.app.shaderString = "texture_test1;scale f "+scale+";moveX f "+moveX+";moveY f "+moveY+ ";rotZ f "+rotZ+ ";lightscale f "+transp;
 $scope.setWidgetProp(widgetName, 'shader', $scope.app.shaderString);
 $scope.view.wdg[widgetName]['opacity'] =transp;
 if(debug) console.info( $scope.app.shaderString)
 $scope.$applyAsync()
 }, jumpInterval, callduration/jumpInterval)},calldelay);

$timeout( () => {$scope.setWidgetProp(widgetName,'shader',"Default")},calldelay+callduration);
};
//
$scope.app.myButtonFunction= function( ){

 
 $scope.app.setShaderNew('modelItem-1', 1.0, 1.0, 0.0,2000,15000)
 $scope.app.setShaderNew('modelItem-2', 1.0, 1.0, 0.0,2000,15000)
 $scope.app.setShaderNew('modelItem-3', 1.0, 0.0, 1.0,2000,15000)
 $scope.app.setShaderNew('modelItem-4', 1.0,-1.0, 0.0,2000,15000)
 $scope.app.setShaderNew('modelItem-5', 1.0, 0.0,-1.0,2000,15000)
// here the new call
 $scope.app.setShaderNew1('modelItem-6', 1.0, 1.0, 0.3, 90.0,2000,15000)
 $scope.app.setShaderNew1('modelItem-7', 1.0, 1.0, 0.3,-90.0,2000,15000)
 
 }

 

So now it will works  with a fluid flow in all directions:

 

2020-06-10_18-17-18.jpg

 

2 replies

21-Topaz I
June 8, 2020

Hi @DenGrz ,

in generally case it is very difficult to display property a fluid flow.

The one possible way I know is to use a shader for the workflow with the map to texture which will move in uv direction.

IN this particular example I think we need 4 different shaders where the texture should move in + and -x and +y and -y for the different parts of the pipe system. Of course we need a picture with a proper texture.

I think in the community we have a post where we did similar techniques

https://community.ptc.com/t5/Vuforia-Studio/Water-flow-visible-after-a-time/m-p/664831#M8186

In this case we need to adapt the direction where the texture is moved according the pipe position and orientation.

The pipe could be a 3D Image /only flat but in 3d space - e.g. 4 images for the different pipes/ or a model which perisist at least of 4 pipe components

We can use  of course one shader but then nwe can set  different flow direction.

Let me check more deeply and will give you feedback /this week

21-Topaz I
June 8, 2020

I want to mention that shaders with GLSL , so far I know , are working only on mobile platforms - IOS and Android. I did not manage yet to get it working on HoloLens.  But I believe this could change.

Currently shaders are possible on the HoloLens but with another tool / MRTK - API https://microsoft.github.io/MixedRealityToolkit-Unity/Documentation/GettingStartedWithTheMRTK.html

Which is not supported in Studio yet.  Therefore, for HoloLens device I have no idea how to implement such shader. I see that dev team is considering and working on such solution  but have no information about the implementation.

If somebody have idea for the HoloLens it will be nice to share it here. Thanks!

21-Topaz I
June 8, 2020

Hi @DenGrz ,

so tested it  and  on a Mobile device seem to work as I suggested in the previous post:

 

So I used a shader definition from the post I mentioned before  in  :https://community.ptc.com/t5/Vuforia-Studio/Simulate-Fluid-Flow/m-p/670205#M8351

I created a small pipeline assembly - where some of the pipes are define as modelItems and I applied there a shader. Here the shader  uses different values for u,v depending on the pipe postion:

 

2020-06-08_15-45-45.jpg

I tested with the follwing code:

 

var debug=false
$scope.val =0;
$scope.val1 =0;
$scope.app.shaderString="texture_test;scale f 2;moveX f 0;moveY f 0;lightscale f 1.0";

$scope.$on('$ionicView.afterEnter',function(){
 
 $scope.$applyAsync()
})

$rootScope.$on('modelLoaded',function(){
 
 
 for(var i=1;i<6;i++){
//$scope.view.wdg['modelItem-'+i]['texture'] = "app/resources/Uploaded/water.jpg?name=Texture0&edge=repeat";
 $scope.view.wdg['modelItem-'+i]['texture'] = "app/resources/Uploaded/wasser.jpg?name=Texture0&edge=repeat"; 
 $scope.view.wdg['modelItem-'+i]['opacity'] =0.5; 
 $scope.setWidgetProp('modelItem-'+i, 'shader', $scope.app.shaderString);}
 
 $scope.$applyAsync()
 
})
////////////

//========================================================
$scope.app.setShaderNew= function(widgetName,xDir,yDir,delay,duration)
{
var calldelay =3000; //3 seconds
var callduration=10000;//10secs
var jumpInterval=5;
 
 if(delay !=undefined) calldelay = delay;
 if(duration !=undefined) callduration = duration;
 
$timeout( () => {
 
 $interval(function() { 
 
 if($scope.val >500) $scope.val =0
 else $scope.val +=1
 
 var scale= 1.0;
 var moveX= $scope.val/500*xDir;
 var moveY= $scope.val/500*yDir;
 var transp= 0.75+0.25*(Math.sin(12.0*Math.PI*$scope.val/500));//6 waves

 
 $scope.app.shaderString = "texture_test;scale f "+scale+";moveX f "+moveX+";moveY f "+moveY+ ";lightscale f "+transp;
 $scope.setWidgetProp(widgetName, 'shader', $scope.app.shaderString);
 $scope.view.wdg[widgetName]['opacity'] =transp;
 if(debug) console.info( $scope.app.shaderString)
 $scope.$applyAsync()
 }, jumpInterval, callduration/jumpInterval)},calldelay);
$timeout( () => {$scope.setWidgetProp(widgetName,'shader',"Default")},calldelay+callduration);
};
//
$scope.app.myButtonFunction= function( ){ 
 $scope.app.setShaderNew('modelItem-1', 1.0, 0.0,2000,15000)
 $scope.app.setShaderNew('modelItem-2', 1.0, 0.0,2000,15000)
 $scope.app.setShaderNew('modelItem-3', 0.0, 1.0,2000,15000)
 $scope.app.setShaderNew('modelItem-4',-1.0, 0.0,2000,15000)
 $scope.app.setShaderNew('modelItem-5', 0.0,-1.0,2000,15000)
 
 }

 

 

The pipeline assemy was created in Creo Parametric and exported to pvz:

 

2020-06-08_16-03-25.jpg

When assembling the pipes , I inserted the components always in the flow direction - means z-axis was in flow direction

Here the shader definition in the tml Text widget:

 

<script name="texture_test" type="x-shader/x-fragment">

 precision mediump float;
uniform sampler2D Texture0;
uniform float lightscale;// light intensity
uniform float scale;
uniform float moveX;
uniform float moveY;
 // determine varying parameters
 varying vec3 N;
 varying vec4 vertexCoord;

 // determine shader input parameters
 uniform vec4 surfaceColor;
 

 const vec3 lightPos = vec3(0.5, 0.5,3.0);//light postion see the pulb in model
 const vec4 ambientColor = vec4(0.5, 0.5, 0.5, 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 the color based on light-source and shadows on model
	 vec2 TexCoord = vec2( vertexCoord )*scale;
 TexCoord.x=TexCoord.x+moveX;
 TexCoord.y=TexCoord.y+moveY;
	 vec4 color = texture2D(Texture0, TexCoord) ;
 gl_FragColor = (ambientColor*lightscale + vec4(dProd)) *color ;// surfaceColor;
 }
 }
</script>

<script name="texture_test" 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>

 

DenGrz1-VisitorAuthor
1-Visitor
June 9, 2020

Yes thats looks very good!

 

And is it also possible to have an red flow and a blue flow e.g for the hot and cold water ?

You use an jpg. for the texture ? There do you find this jpg ?

 

Thanks in advance.

DenGrz1-VisitorAuthor
1-Visitor
June 9, 2020

Hi @RolandRaytchev ,

 

I tested it on my model. But in this moment it doesn´t work.

I have a model with several pipelines and they have different x,y and z coord.

 

I have to change definitely the js code and/ or the tml text ?

 

Thanks in advance.