如何基于父级游戏对象的变换使此计算着色器移动?

时间:2019-07-05 02:29:37

标签: c# unity3d shader hlsl

我在Github上找到了一个很棒的计算着色器(归功于Allen Chou https://github.com/TheAllenChou/unity-cj-lib),并且一直在尝试对其进行修改以供我的游戏使用。我正在尝试使计算着色器实例的位置遵循父GameObject的位置,而不影响计算着色器的形状/运动。

我尝试过的两种方法:

  1. 向计算着色器传递Main.cstransform.parent.position中的变量。然后在着色器行particleBuffer[id.x].position += particleBuffer[id.x].linearVelocity * time.y;上添加传递的transform.parent.position变量。

    这种方法实际上确实可以通过父GameObject变换来移动计算着色器。但是它弄乱了着色器的运动,将其从此变为

    enter image description here

    进入此

    enter image description here

  2. 进一步的研究表明,我需要使用矩阵乘法来使这项工作正确。所以我把它放在Main.cs中:

    private int m_Id;
    public Vector3 scale;
    public Matrix4x4 m;
    

    ,并且在Main.cs OnEnableUpdate中:

    scale = transform.parent.localScale;
    m = transform.parent.localToWorldMatrix *
    Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
    m_shader.SetMatrix(m_Id, m);
    

    以及Main.cs OnEnable中的内容:

    m_Id = Shader.PropertyToID("matrixy");
    

    然后为我放置的计算着色器:

    float4x4 matrixy;
    

    在顶部带有其他变量,最后在着色器的底部,我一直在尝试很多行,例如:

    particleBuffer[id.x].position = mul(matrixy, particleBuffer[id.x].position);
    particleBuffer[id.x].position += particleBuffer[id.x].linearVelocity * time.y;
    

    我对第二种方法的尝试都没有使计算着色器的实例位置响应于父GameObject的位置而移动。

如果您有任何建议,请告诉我。

谢谢您的帮助。


这是示例“湍流Rainbow GPU粒子”中的不变代码。

Main.cs

using UnityEngine;    
using CjLib;

namespace TurbulentRainbowGpuParticles
{
    public class Main : MonoBehaviour
    {
        public ComputeShader m_shader;

        private const int kNumParticles = 10000;

        private ComputeBuffer m_computeBuffer;
        private ComputeBuffer m_instanceArgsBuffer;

        private Mesh m_mesh;
        private Material m_material;
        private MaterialPropertyBlock m_materialProperties;

        private int m_csInitKernelId;
        private int m_csStepKernelId;

        private int m_csParticleBufferId;
        private int m_csScaleId;
        private int m_csDampingId;
        private int m_csSpeedId;
        private int m_csLifetimeId;
        private int m_csNumParticlesId;
        private int m_csTimeId;

        void OnEnable()
        {
            m_mesh = new Mesh();
            m_mesh = PrimitiveMeshFactory.BoxFlatShaded();

            int particleStride = sizeof(float) * 24;
            m_computeBuffer = new ComputeBuffer(kNumParticles, particleStride);

            uint[] instanceArgs = new uint[] { 0, 0, 0, 0, 0 };
            m_instanceArgsBuffer = new ComputeBuffer(1, instanceArgs.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
            instanceArgs[0] = (uint) m_mesh.GetIndexCount(0);
            instanceArgs[1] = (uint) kNumParticles;
            instanceArgs[2] = (uint) m_mesh.GetIndexStart(0);
            instanceArgs[3] = (uint) m_mesh.GetBaseVertex(0);
            m_instanceArgsBuffer.SetData(instanceArgs);


            m_csInitKernelId = m_shader.FindKernel("Init");
            m_csStepKernelId = m_shader.FindKernel("Step");

            m_csParticleBufferId = Shader.PropertyToID("particleBuffer");
            m_csScaleId = Shader.PropertyToID("scale");
            m_csDampingId = Shader.PropertyToID("damping");
            m_csSpeedId = Shader.PropertyToID("speed");
            m_csLifetimeId = Shader.PropertyToID("lifetime");
            m_csNumParticlesId = Shader.PropertyToID("numParticles");
            m_csTimeId = Shader.PropertyToID("time");  

            m_material = new Material(Shader.Find("CjLib/Example/TurbulentRainbowParticle"));
            m_material.enableInstancing = true;
            m_material.SetBuffer(m_csParticleBufferId, m_computeBuffer);
            m_materialProperties = new MaterialPropertyBlock();

            m_shader.SetFloats(m_csScaleId, new float[] { 0.15f, 0.3f });
            m_shader.SetFloat(m_csDampingId, 6.0f);
            m_shader.SetFloats(m_csSpeedId, new float[] { 3.0f, 4.0f, 1.0f, 6.0f });
            m_shader.SetFloats(m_csLifetimeId, new float[] { 0.1f, 0.5f, 0.5f, 0.1f });
            m_shader.SetInt(m_csNumParticlesId, kNumParticles);

            m_shader.SetBuffer(m_csInitKernelId, m_csParticleBufferId, m_computeBuffer);
            m_shader.SetBuffer(m_csStepKernelId, m_csParticleBufferId, m_computeBuffer);

            m_shader.Dispatch(m_csInitKernelId, kNumParticles, 1, 1);
        }

        void Update()
        {
            m_shader.SetFloats(m_csTimeId, new float[] { Time.time, Time.fixedDeltaTime });
            m_shader.Dispatch(m_csStepKernelId, kNumParticles, 1, 1);

            Graphics.DrawMeshInstancedIndirect(m_mesh, 0, m_material, new Bounds(Vector3.zero, 20.0f * Vector3.one), m_instanceArgsBuffer, 0, m_materialProperties, UnityEngine.Rendering.ShadowCastingMode.On);
        }

        void OnDisable()
        {
            if (m_computeBuffer != null)
            {
                 m_computeBuffer.Dispose();
                 m_computeBuffer = null;
            }

            if (m_instanceArgsBuffer != null)
            {
                m_instanceArgsBuffer.Dispose();
                m_instanceArgsBuffer = null;
            }
        }
    }
}

着色器:

#pragma kernel Init
#pragma kernel Step

#include "../../CjLib/Shader/Math/Color.cginc"
#include "../../CjLib/Shader/Math/Math.cginc"
#include "../../CjLib/Shader/Noise/Noise.cginc"

#include "ParticleStruct.cginc"

RWStructuredBuffer<Particle> particleBuffer;

float2 scale;    // (min, max)
float damping;
float4 speed;    // (min linear, max linear, min angular, max angular)
float4 lifetime; // (head, min body, max body, tail)

int numParticles;

[numthreads(1, 1, 1)]
void Init(uint3 id : SV_DispatchThreadID)
{
    float t = float(id.x) / float(numParticles);
    float3 seed = id.x;

    particleBuffer[id.x].position = float3(0.0, 0.0, 0.0);

    float3 rotationAxis = rand_uvec(seed);
    seed = rand_vec(seed);
    float rotationAngle = rand(seed.x) * kPi;
    seed = rand_vec(seed);
    particleBuffer[id.x].rotation = quat_axis_angle(rotationAxis, rotationAngle);

    particleBuffer[id.x].scale = rand_range(seed.x, scale.x, scale.y);
    seed = rand_vec(seed);

    particleBuffer[id.x].damping = damping;

    float3 linearDirection = normalize(rand_vec(seed));
    seed = rand_vec(seed);
    float linearSpeed = rand_range(seed.x, speed.x, speed.y);
    seed = rand_vec(seed);
    particleBuffer[id.x].linearVelocity = linearSpeed * linearDirection;

    float3 angularDirection = rand_uvec(seed);
    seed = rand_vec(seed);
    float angularSpeed = rand_range(seed.x, speed.z, speed.w);
    seed = rand_vec(seed);
    particleBuffer[id.x].angularVelocity = quat_axis_angle(angularDirection, angularSpeed);

    float lifetimeBody = rand_range(seed.x, lifetime.y, lifetime.z);
    seed = rand_vec(seed);
    float lifetimeCurrent = -t * (lifetime.x + lifetime.z + lifetime.w);
    particleBuffer[id.x].lifetime = float4(lifetime.x, lifetimeBody, lifetime.w, lifetimeCurrent);

    particleBuffer[id.x].color = float4(hsv2rgb(float3(t, 1.0, 1.0)), 1.0);
}

float2 time; // (current, delta)

[numthreads(1, 1, 1)]
void Step(uint3 id : SV_DispatchThreadID)
{
    // respawn particle
    float prevLife = particleBuffer[id.x].lifetime.w;
    particleBuffer[id.x].lifetime.w += time.y;
    float4 lifetime = particleBuffer[id.x].lifetime;
    float totalLife = dot(lifetime.xyz, float3(1.0, 1.0, 1.0));
    if (lifetime.w > totalLife)
    {
        // easy way to achieve sub-frame interpolation
        lifetime.w -= totalLife;
        time.x += lifetime.w;

        float3 seed = id.x + time.x;

        float3 emitterPos = float3(6.0 * sin(3.0 * time.x), 1.0 * sin(6.0 * time.x), 1.0 * sin(6.0 * time.x));
        particleBuffer[id.x].position = emitterPos;
        particleBuffer[id.x].lifetime.w = 0.0;

        float3 linearDirection = normalize(rand_vec(seed));
        seed = rand_vec(seed);
        float linearSpeed = rand_range(seed.x, speed.x, speed.y);
        seed = rand_vec(seed);
        particleBuffer[id.x].linearVelocity = linearSpeed * linearDirection;

        float3 angularDirection = rand_uvec(seed);
        seed = rand_vec(seed);
        float angularSpeed = rand_range(seed.x, speed.z, speed.w);
        seed = rand_vec(seed);
        particleBuffer[id.x].angularVelocity = quat_axis_angle(angularDirection, angularSpeed);
    }

    if (lifetime.w < 0.0)
        return;

    // turbulence
    float3 turbulence = snoise_grad(0.4 * particleBuffer[id.x].position, float3(0.0, time.x, 0.0), 2, 1.2).xyz;
    particleBuffer[id.x].linearVelocity += 0.3f * turbulence;

    // integrate
    particleBuffer[id.x].position += particleBuffer[id.x].linearVelocity * time.y;
    float4 q = quat_pow(particleBuffer[id.x].angularVelocity, time.y);
    particleBuffer[id.x].rotation = quat_concat(q, particleBuffer[id.x].rotation);

    // damping
    float d = 1.0 - particleBuffer[id.x].damping * time.y;
    particleBuffer[id.x].linearVelocity *= d;
}

0 个答案:

没有答案