Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Mobile Suggestions + Help
#1
I've read all over your forums and website that the regular Obi Fluid Rendered is too much for mobile devices. 

Seems like 3d would really useful for mobile devices, but I can make 2d work for what I need if I can address these issues.

I don't know shaders that well at all, but if I use the simple renderer I need to add depth or the particles will get drawn over objects.  I haven't the faintest idea on how to do this. Any help?

-

The Raclette demo is perfect for what I'm going for, but that doesn't seem to work in 2D. Basically I have lava that "cools" and turns black as it stops moving. What would be my best option to do that? Any way I can detect this is happening so I can spawn smoke from these areas?

Thanks for your help.
Reply
#2
If anything I would love some help getting a really simple depth for the simple renderer.
Reply
#3
(04-10-2019, 06:24 PM)neecko Wrote: If anything I would love some help getting a really simple depth for the simple renderer.

Hi,

To get a shader to write a custom value to the depth buffer, you need to change its output from "float4" or "fixed4" to "fout". Then, inside the fragment shader declare a fout instance (as it is a struct, containing both color and depth). Set both its color and depth to the values you desire.

Now, for finding the correct depth value you need to output from the fluid shader, you need to write the particle's depth values to a render texture. So declare a new depth render texture in the SimpleFluidRenderer's command buffer (copy-pasted from the regular Fluid Renderer):

Code:
int depth = Shader.PropertyToID("_FluidDepthTexture");
renderFluid.GetTemporaryRT(depth,-1,-1,24,FilterMode.Point,RenderTextureFormat.Depth);

Then you need to render the particles to it:
Code:
renderFluid.SetRenderTarget(depth); // fluid depth
¡renderFluid.ClearRenderTarget(true,true,Color.clear); //clear
            
// draw fluid depth texture:
foreach(ObiParticleRenderer renderer in particleRenderers){
    if (renderer != null){
        foreach(Mesh mesh in renderer.ParticleMeshes){
            if (renderer.ParticleMaterial != null)
                renderFluid.DrawMesh(mesh,Matrix4x4.identity,renderer.ParticleMaterial,0,0);
        }
    }
}

Lastly, ObiFluids.cginc contains helper functions to get eye space data -position and normal- for a fluid fragment (SetupEyeSpaceFragment) and to compute the depth value from the eye space position of a fragment (OutputFragmentDepth). You can use them in the fluid shader to output the correct depth value (do not forget to #include "ObiFluids.cginc"):

Code:
fout fo;
float3 eyePos,eyeNormal;
float thickness = SetupEyeSpaceFragment(i.uv,eyePos,eyeNormal);

//...rest of your fluid fragment shader here...

fo.color = fluidColor; //set your fluid color
OutputFragmentDepth(eyePos,fo); // this will write the correct depth value to fo.depth
return fo;
Reply
#4
(05-10-2019, 11:30 AM)josemendez Wrote: Hi,

To get a shader to write a custom value to the depth buffer, you need to change its output from "float4" or "fixed4" to "fout". Then, inside the fragment shader declare a fout instance (as it is a struct, containing both color and depth). Set both its color and depth to the values you desire.

Now, for finding the correct depth value you need to output from the fluid shader, you need to write the particle's depth values to a render texture. So declare a new depth render texture in the SimpleFluidRenderer's command buffer (copy-pasted from the regular Fluid Renderer):

Code:
int depth = Shader.PropertyToID("_FluidDepthTexture");
renderFluid.GetTemporaryRT(depth,-1,-1,24,FilterMode.Point,RenderTextureFormat.Depth);

Then you need to render the particles to it:
Code:
renderFluid.SetRenderTarget(depth); // fluid depth
¡renderFluid.ClearRenderTarget(true,true,Color.clear); //clear
            
// draw fluid depth texture:
foreach(ObiParticleRenderer renderer in particleRenderers){
    if (renderer != null){
        foreach(Mesh mesh in renderer.ParticleMeshes){
            if (renderer.ParticleMaterial != null)
                renderFluid.DrawMesh(mesh,Matrix4x4.identity,renderer.ParticleMaterial,0,0);
        }
    }
}

Lastly, ObiFluids.cginc contains helper functions to get eye space data -position and normal- for a fluid fragment (SetupEyeSpaceFragment) and to compute the depth value from the eye space position of a fragment (OutputFragmentDepth). You can use them in the fluid shader to output the correct depth value (do not forget to #include "ObiFluids.cginc"):

Code:
fout fo;
float3 eyePos,eyeNormal;
float thickness = SetupEyeSpaceFragment(i.uv,eyePos,eyeNormal);

//...rest of your fluid fragment shader here...

fo.color = fluidColor; //set your fluid color
OutputFragmentDepth(eyePos,fo); // this will write the correct depth value to fo.depth
return fo;

I am not at all familiar with Shaders. This has been giving me a lot of grief. 

Here is the SimpleRenderer

Code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Rendering;


namespace Obi
{
    /**
     * Very simple 2D only fluid rendering. This simply draws particles additively to a thickness texture,
     * and uses the result to tint and refract the background. Does not perform z-testing against the scene depth buffer,
     * does not calculate lightning, foam, or transmission/reflection effects.
     */
    public class ObiSimpleFluidRenderer : ObiBaseFluidRenderer
    {
    
        [Range(0.01f,2)]
        public float thicknessCutoff = 1.2f;

        private Material thickness_Material;
        public Material fluidMaterial;
                
        protected override void Setup(){

           GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
            
            if (thickness_Material == null)
            {
                thickness_Material = CreateMaterial(Shader.Find("Hidden/FluidThickness"));
            }
    
            bool shadersSupported = thickness_Material;
    
            if (!shadersSupported ||
                !SystemInfo.supportsImageEffects)
            {
                enabled = false;
                Debug.LogWarning("Obi Simple Fluid Renderer not supported in this platform.");
                return;
            }
    
            if (fluidMaterial != null)
            {        
                fluidMaterial.SetFloat("_ThicknessCutoff", thicknessCutoff);
            }
        }
    
        protected override void Cleanup()
        {
            if (thickness_Material != null)
                Object.DestroyImmediate (thickness_Material);
        }
    
        public override void UpdateFluidRenderingCommandBuffer()
        {
    
            renderFluid.Clear();
    
            if (particleRenderers == null || fluidMaterial == null)
                return;
            
            // declare buffers:
            int refraction = Shader.PropertyToID("_Refraction");
            int thickness = Shader.PropertyToID("_Thickness");
           int depth = Shader.PropertyToID("_FluidDepthTexture");

           // get RTs (at half resolution):
           renderFluid.GetTemporaryRT(refraction,-2,-2,0,FilterMode.Bilinear);
            renderFluid.GetTemporaryRT(thickness,-2,-2,0,FilterMode.Bilinear);
           renderFluid.GetTemporaryRT(depth, -1, -1, 24, FilterMode.Point, RenderTextureFormat.Depth);

           // render background:
           renderFluid.Blit (BuiltinRenderTextureType.CurrentActive, refraction);

           //Depth
           renderFluid.SetRenderTarget(depth); // fluid depth
           renderFluid.ClearRenderTarget(true, true, Color.clear); //clear

           // draw fluid depth texture:
           foreach (ObiParticleRenderer renderer in particleRenderers)
           {
               if (renderer != null)
               {
                   foreach (Mesh mesh in renderer.ParticleMeshes)
                   {
                       if (renderer.ParticleMaterial != null)
                           renderFluid.DrawMesh(mesh, Matrix4x4.identity, renderer.ParticleMaterial, 0, 0);
                   }
               }
           }

           // render particle thickness to alpha channel of thickness buffer:
           renderFluid.SetRenderTarget(thickness);
            renderFluid.ClearRenderTarget(true,true,Color.clear);
            foreach(ObiParticleRenderer renderer in particleRenderers){
                if (renderer != null){
    
                    renderFluid.SetGlobalColor("_ParticleColor",renderer.particleColor);
                    renderFluid.SetGlobalFloat("_RadiusScale",renderer.radiusScale);
    
                    foreach(Mesh mesh in renderer.ParticleMeshes){
                        renderFluid.DrawMesh(mesh,Matrix4x4.identity,thickness_Material,0,0);
                    }
                }
            }
    
            // final composite:
            renderFluid.Blit(refraction,BuiltinRenderTextureType.CameraTarget,fluidMaterial);  
    
        }
    
    }
}

The shader I'm at a loss with. 

Code:
Shader "Obi/Fluid/Simple2DFluidDepth"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _RefractionCoeff ("Refraction", Range (-0.1, 0.1)) = 0.01
        _Color ("Fluid color", Color) = (0.3,0.6,1,1)
        _ThicknessScale ("ThicknessScale", Range (0, 30)) = 5
    }

    SubShader
    {
        Pass
        {

            Name "SimpleFluid"
            Tags {"LightMode" = "ForwardBase"}

            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0

            #include "ObiFluids.cginc"
            #include "ObiParticles.cginc"

            sampler2D _Refraction;
            float _ThicknessScale;
            fixed4 _Color;
            float _RefractionCoeff;

            struct vin
            {
                float4 pos : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : POSITION;
            };

            v2f vert (vin v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.pos);
                o.uv = v.uv;

                return o;
            }

            fout frag (v2f i) : COLOR
            {
                fout fo;
                
                float3 eyePos,eyeNormal;
                float thickness = SetupEyeSpaceFragment(i.uv,eyePos,eyeNormal);

                fixed4 fluid = tex2D(_Thickness,i.uv);
                // basic thickness-driven refraction:
                fixed4 output = tex2D(_Refraction,i.uv + _RefractionCoeff*fluid.a);  

                // thresholding for cheap metaball-like effect
                if (fluid.a * 10 < _ThicknessCutoff)
                    discard;

                fo.color = _Color; //set your fluid color
               OutputFragmentDepth(eyePos,fo); // this will write the correct depth value to fo.depth
               return fo;
            }
            ENDCG
        }        

    }
}
}


Any help?

Cheers
Reply
#5
I'm still stuck. Not having any luck
Reply