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

SOLVED
Highlighted

## Simulate Fluid Flow

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.

1 ACCEPTED SOLUTION

Accepted Solutions
Highlighted Opal
(in response to DenGrz)

## Re: Simulate Fluid Flow

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;
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>

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.\$applyAsync()
...
//========================================================
{
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.view.wdg[widgetName]['opacity'] =transp;
\$scope.\$applyAsync()
}, jumpInterval, callduration/jumpInterval)},calldelay);

};
//
\$scope.app.myButtonFunction= function( ){

// here the new call

}``````

So now it will works  with a fluid flow in all directions: 15 REPLIES 15
Highlighted Opal
(in response to DenGrz)

## Re: Simulate Fluid Flow

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

Highlighted Opal
(in response to RolandRaytchev)

## Re: Simulate Fluid Flow

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!

Highlighted Opal
(in response to DenGrz)

## Re: Simulate Fluid Flow

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: 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()
})

for(var i=1;i<6;i++){
\$scope.view.wdg['modelItem-'+i]['opacity']  =0.5;

\$scope.\$applyAsync()

})
////////////

//========================================================
{
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.view.wdg[widgetName]['opacity'] =transp;
\$scope.\$applyAsync()
}, jumpInterval, callduration/jumpInterval)},calldelay);
};
//
\$scope.app.myButtonFunction= function( ){

}``````

The pipeline assemy was created in Creo Parametric and exported to pvz: 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;

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>

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>``````

Highlighted

## Re: Simulate Fluid Flow

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 ?

Highlighted

## Re: Simulate Fluid Flow

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 ?

Highlighted Opal
(in response to DenGrz)

## Re: Simulate Fluid Flow

Hi @DenGrz ,

no Idea what could be the problem.

As mentioned it should work only on mobile platform (preview, ios and android) but not on HoloLens device.

Here attached the sample project. May be you can test if it works in your environment and if it works then see what is the difference. Then ,please , let me know if you have success with it. Thanks!

Highlighted

## Re: Simulate Fluid Flow

I tested it with the sample project and it works perferctly. Thanks for it!

Now i would like to include one thing.

I would like to bring more modelIteams with an other jpg.

I copy and paste the same code but with the new modelIteams and the other jpg.

`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<13;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 secondsvar callduration=10000;//10secsvar jumpInterval=250;if(delay !=undefined) calldelay = delay;if(duration !=undefined) callduration = duration;\$timeout( () => {\$interval(function() { if(\$scope.val >500) \$scope.val =0else \$scope.val +=1var 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)}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<13;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/Fluid_Blau.png?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 secondsvar callduration=10000;//10secsvar jumpInterval=250;if(delay !=undefined) calldelay = delay;if(duration !=undefined) callduration = duration;\$timeout( () => {\$interval(function() { if(\$scope.val >500) \$scope.val =0else \$scope.val +=1var 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-6', 0.0,-1.0,2000,15000)\$scope.app.setShaderNew('modelItem-7', 0.0,-1.0,2000,15000)\$scope.app.setShaderNew('modelItem-8', 0.0,-1.0,2000,15000)\$scope.app.setShaderNew('modelItem-9', 0.0,-1.0,2000,15000)\$scope.app.setShaderNew('modelItem-10', 0.0,-1.0,2000,15000)\$scope.app.setShaderNew('modelItem-11', 0.0,-1.0,2000,15000)\$scope.app.setShaderNew('modelItem-12', 0.0,-1.0,2000,15000)}`

In the modelIteam 6-12 i see the flow, but modelIteam 1-5 is nothing.

There can be my mistake?

Highlighted Opal
(in response to DenGrz)

## Re: Simulate Fluid Flow

I am not sure, but it seems that you copied the whole code 2 times / when I interperted correctly you message. In this case you will override partially the code from modelItem 1-5 by the second code and the initialization of item 1- 5 were lost.

You need to use the same code but for more items e.g.:

``````scope.app.myButtonFunction= function( ){

}``````

Also it depends on the size of the picture and also on the creation of the model , how is the position of the texture uv coordinates. But this to be tested more detailed on the test project.

Highlighted

## Re: Simulate Fluid Flow

OK. With the same jpg file for alle modelIteams it work perfect.

And if i would like to have for the different modelIteams use other jpg´s.

How would be the js code ?

E.g i tested it like the following code. But it doesn´t work so.

` for(var i=1;i<13;i++){//\$scope.view.wdg['modelItem-'+i]['texture'] = "app/resources/Uploaded/water.jpg?name=Texture0&edge=repeat";\$scope.view.wdg['modelItem-1']['texture'] = "app/resources/Uploaded/wasser.jpg?name=Texture0&edge=repeat"; \$scope.view.wdg['modelItem-1']['opacity'] =0.5; \$scope.setWidgetProp('modelItem-1', 'shader', \$scope.app.shaderString);}\$scope.view.wdg['modelItem-2']['texture'] = "app/resources/Uploaded/Fluid_Blau.png?name=Texture0&edge=repeat"; \$scope.view.wdg['modelItem-2']['opacity'] =0.5; \$scope.setWidgetProp('modelItem-2', 'shader', \$scope.app.shaderString);}\$scope.view.wdg['modelItem-3']['texture'] = "app/resources/Uploaded/Fluid_Blau.png?name=Texture0&edge=repeat"; \$scope.view.wdg['modelItem-3']['opacity'] =0.5; \$scope.setWidgetProp('modelItem-3', 'shader', \$scope.app.shaderString);}\$scope.\$applyAsync()})////////////`

In this example the modelIteam 2 and 3 had a other jpg file.

How can be the right code looks like?

Highlighted Opal
(in response to DenGrz)

## Re: Simulate Fluid Flow

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;
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>

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.\$applyAsync()
...
//========================================================
{
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.view.wdg[widgetName]['opacity'] =transp;
\$scope.\$applyAsync()
}, jumpInterval, callduration/jumpInterval)},calldelay);

};
//
\$scope.app.myButtonFunction= function( ){

// here the new call

}``````

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

## Re: Simulate Fluid Flow

Yes that´s looks very good.

Could you please send me the updated sample project ?

Thanks!

Highlighted Opal
(in response to DenGrz)

## Re: Simulate Fluid Flow

Sure, here I attached the updated project (Studio ) . If required I could provide the Creo (7.0) assembly- in this case , please, let me know.

Highlighted Opal
(in response to DenGrz)

## Re: Simulate Fluid Flow

I did simple searcheon google water pictures

So if you search for "red water pictures" - you can find  some pictures 2-3 pictures which could be used- need to have a wave  texture  to see beter the flow when you move the texture in x or y direction.

Highlighted Opal
(in response to RolandRaytchev)

## Re: Simulate Fluid Flow

sorry I did answer only for the first part of your question. Need to check more detailed.

I think it depends on the size an on the texture structure. Could you privde the files/ textures where it does not work

In generally the same code should work for all - mapping from 0-1 but may it requires for different sizes of the pictures which is used as texture different ratio  for the mapping parameter in the texture.  So I need to check it more detailed on the sample picutures wher it does not work

Highlighted

## Re: Simulate Fluid Flow

yes. It looks exactly like I've imagined.

If you could send the updated sample project ?