mlavik1 / UnityVolumeRendering

Volume rendering, implemented in Unity3D. Want to support the project? Donate a small sum to Save The Children(https://www.savethechildren.net/) or another charity, and send me a message, and I will be greatly motivated!
https://fosstodon.org/@unityvolrend
MIT License
428 stars 123 forks source link

Rendering for one eye - Unity + virtual reality #54

Open sebstax opened 2 years ago

sebstax commented 2 years ago

Hello,

I have a virtual reality headset (HP reverb G2) an I built an application with Unity 2020 using your plug in.

When I try the application with my VR headset, it only render my model (a DICOM which I converted as a RAW otherwise impossible to load) for the the left eye.

Is there something to modify about the shader?

Many thanks in advance

stefano-pittalis commented 2 years ago

Hi @sebstax, try changing the pixel and fragment input structs this way:

struct vert_in
{
   float4 vertex : POSITION;
   float4 normal : NORMAL;
   float2 uv : TEXCOORD0;
   UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct frag_in
{
   float4 vertex : SV_POSITION;
   float2 uv : TEXCOORD0;
   float3 vertexLocal : TEXCOORD1;
   float3 normal : NORMAL;
   UNITY_VERTEX_INPUT_INSTANCE_ID
   UNITY_VERTEX_OUTPUT_STEREO
};

Then, change the vertex shader:

frag_in vert_main(vert_in v)
{
   frag_in o;

   UNITY_SETUP_INSTANCE_ID(v);
   UNITY_TRANSFER_INSTANCE_ID(v, o);
   UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

   o.vertex = UnityObjectToClipPos(v.vertex);
   o.uv = v.uv;
   o.vertexLocal = v.vertex;
   o.normal = UnityObjectToWorldNormal(v.normal);
   return o;
}

Adding those missing macros should fix the problem!

sebstax commented 2 years ago

Thank you for the quick feedback,

I just have to copy past this code anywhere or in a specific function? (I'am not familiar with shader development)

Many thanks

stefano-pittalis commented 2 years ago

You should go and copy these macros in all the shaders that are actually present in the scene, and that you want to view in AR (this setup must be done not only for this specific project, but it is a pre-requisite to do for all the shaders that must be viewable in VR / AR in Unity).

Usually in a standard shader you should always find at least two structs, which act as inputs for the vertex shader, and the fragment shader.

What you should do is copy the macros I indicated above into these structs (they are usually easy to find, as they specify some semantics).

// Input vertex shader
struct vert_in
{
    float4 vertex : POSITION;
    float4 normal : NORMAL;
    float2 uv : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID  // Line to add
};

// Input fragment shader
struct frag_in
{
    float4 vertex : SV_POSITION;
    float2 uv : TEXCOORD0;
    float3 vertexLocal : TEXCOORD1;
    float3 normal : NORMAL;
    UNITY_VERTEX_INPUT_INSTANCE_ID  // Line to add
    UNITY_VERTEX_OUTPUT_STEREO      // Line to add
};

The last modification must instead be carried out directly in the vertex shader (also easily recognizable because it accepts one of the aforementioned structs as input, and returns the other as output)

// Vertex shader
frag_in vert_main(vert_in v)
{
    frag_in o;

    UNITY_SETUP_INSTANCE_ID(v);                                // Line to add
    UNITY_TRANSFER_INSTANCE_ID(v, o);                     // Line to add
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);     // Line to add

    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = v.uv;
    o.vertexLocal = v.vertex;
    o.normal = UnityObjectToWorldNormal(v.normal);
    return o;
}

If there were any doubts about what the function for the vertex shader actually is, inside the shader you should also find a pragma directive with expressly indicated the name of the method that acts as vertex shader:

#pragma vertex <function_name>
sebstax commented 2 years ago

Thank you it works for the volumetric model :)

However,I'm stuck to get stereo for SlicingPlane function when added in Unity hierarchy Do you have an idea?

It is about the shader "SliceRenderingshader"

I try to replace by the code mention here but it does not work :

https://unity.com/how-to/best-practices-vr-and-mobile-ar-graphics#changes-vertex-shader-code

Code is :

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "VolumeRendering/SliceRenderingShader" { Properties { _DataTex("Data Texture (Generated)", 3D) = "" {} _TFTex("Transfer Function Texture", 2D) = "white" {} } SubShader { Tags { "Queue" = "Transparent" } LOD 100 Cull Off

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
        };

        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
            float4 relVert : TEXCOORD1;
        };

        sampler3D _DataTex;
        sampler2D _TFTex;
        // Parent's inverse transform (used to convert from world space to volume space)
        uniform float4x4 _parentInverseMat;
        // Plane transform
        uniform float4x4 _planeMat;

        v2f vert (appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            // Calculate plane vertex world position.
            float3 vert = mul(_planeMat, float4(0.5f -v.uv.x, 0.0f, 0.5f -v.uv.y, 1.0f));
            // Convert from world space to volume space.
            o.relVert = mul(_parentInverseMat, float4(vert, 1.0f));
            o.uv = v.uv;
            return o;
        }

        fixed4 frag (v2f i) : SV_Target
        {
            float3 dataCoord = i.relVert + float3(0.5f, 0.5f, 0.5f);
            // If the current fragment is outside the volume, simply colour it black.
            // Note: Unity does not seem to have support for clamping texture coordinates to a border value, so we have to do this manually
            if (dataCoord.x > 1.0f || dataCoord.y > 1.0f || dataCoord.z > 1.0f || dataCoord.x < 0.0f || dataCoord.y < 0.0f || dataCoord.z < 0.0f)
            {
               return float4(0.0f, 0.0f, 0.0f, 1.0f);
            }
            else
            {
               // Sample the volume texture.
               float dataVal = tex3D(_DataTex, dataCoord);
               float4 col = tex2D(_TFTex, float2(dataVal, 0.0f));
               col.a = 1.0f;
               return col;
            }
        }
        ENDCG
    }
}

}

mlavik1 commented 2 years ago

Just writing to let you know that I'd like to help, but that I currently don't have a VR headset.. But I plan to get one, so hopefully I can be more helpful then :) I only tried to use this project in VR once, but that was a while ago, so I didn't know this was an issue now. Definitely worth getting fixed, so thanks a lot (to both of you) for sharing this info. But this only happens when using "single-pass instancing" rendering, right?

sebstax commented 2 years ago

@mlavik1 Thank you for your feedback.

I changed the render mode for "multi pass" and it fixed the issue :)

Thank you very much for bringing my attention on the render mode! Indeed it was set up as "single pass".

chiarapalu commented 2 years ago

Hi All, I'm facing the same problem switching to unity2020. I already edited the macros as @stefano-pittalis was suggesting but it is still not working. Using XRSDK I don't have anymore the option to choose btw single or multi pass rendering. What am I missing? Thanks!! Here the code for the SliceRenderingShader.shader

// Upgrade NOTE: replaced 'UNITY_INSTANCE_ID' with 'UNITY_VERTEX_INPUT_INSTANCE_ID'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "VolumeRendering/SliceRenderingShader" { Properties { _DataTex("Data Texture (Generated)", 3D) = "" {} _TFTex("Transfer Function Texture", 2D) = "white" {} } SubShader { Tags { "Queue" = "Transparent" } LOD 100 Cull Off

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
            UNITY_VERTEX_INPUT_INSTANCE_ID   //added
        };

        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
            float4 relVert : TEXCOORD1;
            UNITY_VERTEX_INPUT_INSTANCE_ID   //added
            UNITY_VERTEX_OUTPUT_STEREO  //added
        };

        sampler3D _DataTex;
        sampler2D _TFTex;
        uniform float4x4 _parentInverseMat;
        uniform float4x4 _planeMat;

        v2f vert (appdata v)
        {
            v2f o;
            float3 vert = float3(-v.uv.x, 0.0f, -v.uv.y) + float3(0.5f, 0.0f, 0.5f);
            vert = mul(_planeMat, float4(vert, 1.0f));
            //o.vertex = mul(UNITY_MATRIX_VP, float4(vert, 1.0f));
            //added-----------------
            UNITY_SETUP_INSTANCE_ID(v);         
            UNITY_TRANSFER_INSTANCE_ID(v, o);
            UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
            //added---------------------
            o.vertex = UnityObjectToClipPos(v.vertex);;
            o.relVert = mul(_parentInverseMat, float4(vert, 1.0f));
            o.uv = v.uv;
            return o;
        }

        UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex);

        fixed4 frag (v2f i) : SV_Target
        {
            UNITY_SETUP_INSTANCE_ID(i); //added
            float3 dataCoord = i.relVert +float3(0.5f, 0.5f, 0.5f);
            float dataVal = tex3D(_DataTex, dataCoord);
            float4 col = tex2D(_TFTex, float2(dataVal, 0.0f));
            col.a = 1.0f;

            return col;
        }
        ENDCG
    }
}

}

QY0911 commented 1 year ago

Hi All, I'm facing the same problem switching to unity2020. I already edited the macros as @stefano-pittalis was suggesting but it is still not working. Using XRSDK I don't have anymore the option to choose btw single or multi pass rendering. What am I missing? Thanks!! Here the code for the SliceRenderingShader.shader

// Upgrade NOTE: replaced 'UNITY_INSTANCE_ID' with 'UNITY_VERTEX_INPUT_INSTANCE_ID'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "VolumeRendering/SliceRenderingShader" { Properties { _DataTex("Data Texture (Generated)", 3D) = "" {} _TFTex("Transfer Function Texture", 2D) = "white" {} } SubShader { Tags { "Queue" = "Transparent" } LOD 100 Cull Off

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
            UNITY_VERTEX_INPUT_INSTANCE_ID   //added
        };

        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
            float4 relVert : TEXCOORD1;
            UNITY_VERTEX_INPUT_INSTANCE_ID   //added
            UNITY_VERTEX_OUTPUT_STEREO  //added
        };

        sampler3D _DataTex;
        sampler2D _TFTex;
        uniform float4x4 _parentInverseMat;
        uniform float4x4 _planeMat;

        v2f vert (appdata v)
        {
            v2f o;
            float3 vert = float3(-v.uv.x, 0.0f, -v.uv.y) + float3(0.5f, 0.0f, 0.5f);
            vert = mul(_planeMat, float4(vert, 1.0f));
            //o.vertex = mul(UNITY_MATRIX_VP, float4(vert, 1.0f));
            //added-----------------
            UNITY_SETUP_INSTANCE_ID(v);         
            UNITY_TRANSFER_INSTANCE_ID(v, o);
            UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
            //added---------------------
            o.vertex = UnityObjectToClipPos(v.vertex);;
            o.relVert = mul(_parentInverseMat, float4(vert, 1.0f));
            o.uv = v.uv;
            return o;
        }

        UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex);

        fixed4 frag (v2f i) : SV_Target
        {
            UNITY_SETUP_INSTANCE_ID(i); //added
            float3 dataCoord = i.relVert +float3(0.5f, 0.5f, 0.5f);
            float dataVal = tex3D(_DataTex, dataCoord);
            float4 col = tex2D(_TFTex, float2(dataVal, 0.0f));
            col.a = 1.0f;

            return col;
        }
        ENDCG
    }
}

} Hi, I met the same issue, how did you solve it? Thank you.