Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Clip one cube with two plane arrays and keep positive sides?

Discussion in 'Shaders' started by Meaningless-Trinket, Sep 22, 2023.

  1. Meaningless-Trinket

    Meaningless-Trinket

    Joined:
    Apr 25, 2020
    Posts:
    81
    I'm looking for a way to clip with plane arrays for my project.

    The test code works, but not in my project.

    The effect I am going for is each array of planes has it's own object to clip.

    How do I clip one cube with two plane arrays and keep the positive sides?

    My test code.
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using UnityEngine;
    5.  
    6. public class clipcube : MonoBehaviour
    7. {
    8.     public GameObject Cube;
    9.  
    10.     public Vector4[] PlanePos;
    11.  
    12.     public MaterialPropertyBlock BlockOne;
    13.  
    14.     public List<Plane> planes = new List<Plane>();
    15.  
    16.     // Start is called before the first frame update
    17.     void Start()
    18.     {
    19.         PlanePos = new Vector4[10];
    20.  
    21.         BlockOne = new MaterialPropertyBlock();
    22.  
    23.         planes.Add(new Plane(new Vector3(5,0,0), new Vector3(5,0, -1), new Vector3(5, 1, -1)));
    24.  
    25.         planes.Add(new Plane(new Vector3(-5, 1, -1), new Vector3(-5, 0, -1), new Vector3(-5, 0, 0)));
    26.     }
    27.        
    28.  
    29.     // Update is called once per frame
    30.     void Update()
    31.     {
    32.         for (int i = 0; i < planes.Count; i++)
    33.         {
    34.             BlockOne.SetInt("_Int", planes.Count);
    35.  
    36.             Array.Clear(PlanePos, 0, PlanePos.Length);
    37.  
    38.             PlanePos[i] = new Vector4(planes[i].normal.x, planes[i].normal.y, planes[i].normal.z, planes[i].distance);
    39.  
    40.             Matrix4x4 matrix = Matrix4x4.TRS(Cube.transform.position, Cube.transform.rotation, Cube.transform.lossyScale);
    41.  
    42.             Graphics.DrawMesh(Cube.GetComponent<MeshFilter>().mesh, matrix, Cube.GetComponent<Renderer>().sharedMaterial, 0, Camera.main, 0, BlockOne, false, false);
    43.  
    44.             BlockOne.SetVectorArray("_Plane", PlanePos);
    45.         }
    46.     }
    47. }
    My shader
    Code (CSharp):
    1. Shader "Custom/Clipping"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic ("Metallic", Range(0,1)) = 0.0
    9.         [HDR]_Emission ("Emission", color) = (0,0,0)
    10.     }
    11.     SubShader
    12.     {
    13.         Tags { "RenderType"="Opaque" }
    14.         LOD 200
    15.  
    16.         CGPROGRAM
    17.         // Physically based Standard lighting model, and enable shadows on all light types
    18.         #pragma surface surf Standard fullforwardshadows
    19.  
    20.         // Use shader model 3.0 target, to get nicer looking lighting
    21.         #pragma target 3.0
    22.  
    23.         sampler2D _MainTex;
    24.  
    25.         struct Input
    26.         {
    27.             float2 uv_MainTex;
    28.             float3 worldPos;
    29.         };
    30.  
    31.         half _Glossiness;
    32.         half _Metallic;
    33.         fixed4 _Color;
    34.         int _Int = 0;
    35.         float4 _Plane[50];
    36.         half3 _Emission;
    37.  
    38.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    39.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    40.         // #pragma instancing_options assumeuniformscaling
    41.         UNITY_INSTANCING_BUFFER_START(Props)
    42.             // put more per-instance properties here
    43.         UNITY_INSTANCING_BUFFER_END(Props)
    44.  
    45.         void surf (Input IN, inout SurfaceOutputStandard o)
    46.         {
    47.             for (int i = 0; i < _Int; i++)
    48.             {
    49.                 float distance = dot(IN.worldPos, _Plane[i].xyz);
    50.                 distance = distance + _Plane[i].w;
    51.                 clip(distance);
    52.             }
    53.             // Albedo comes from a texture tinted by color
    54.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    55.             o.Albedo = c.rgb;
    56.             // Metallic and smoothness come from slider variables
    57.             o.Metallic = _Metallic;
    58.             o.Smoothness = _Glossiness;
    59.             o.Alpha = c.a;
    60.             o.Emission = _Emission * tex2D(_MainTex, IN.uv_MainTex);
    61. }
    62.         ENDCG
    63.     }
    64.     FallBack "Diffuse"
    65. }
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,306
    The update loop doesn't make any sense to me. You're rendering one cube multiple times, once for each plane in the array, only assigning one plane in each loop, but also setting the material to iterate over the array as if all of the planes are there. You're also not setting the plane array in the property block until after adding the DrawMesh command, meaning the first draw won't have any plane data! The property block is copied when you call DrawMesh, so any modifications you make after calling DrawMesh are ignored by the call.

    If the code was modified to properly draw the cube once for each plane, the result would be you'd still just see a solid cube except where the planes intersect, as the rest of the cube is still being rendered each time.

    To me it seems like you want to do this:
    Code (csharp):
    1. void Update()
    2. {
    3.   BlockOne.SetInt("_Int", planes.Count);
    4.   Array.Clear(planePos, 0, planes.Count);
    5.   for (int i=0; i<planes.Count; i++)
    6.     planePos[i] = new Vector4(planes[i].normal.x, planes[i].normal.y, planes[i].normal.z, planes[i].distance);
    7.   BlockOne.SetVectorArray("_Plane", planePos);
    8.   Matrix4x4 matrix = Matrix4x4.TRS(Cube.transform.position, Cube.transform.rotation, Cube.transform.lossyScale);
    9.   Graphics.DrawMesh(Cube.GetComponent<MeshFilter>().mesh, matrix, Cube.GetComponent<Renderer>().sharedMaterial, 0, Camera.main, 0, BlockOne, false, false);
    10. }
     
  3. Meaningless-Trinket

    Meaningless-Trinket

    Joined:
    Apr 25, 2020
    Posts:
    81
    Thank you, I set the vector array and now the project works.