private static void SetParticleParam(PartSysEmitter emitter, int particleIdx, PartSysParamId id,
                                         float atLifetime, ParticleStateField stateField, float defaultValue)
    {
        var value = GetParticleValue(emitter, particleIdx, id, atLifetime, defaultValue);

        emitter.GetParticleState().SetState(stateField, particleIdx, value);
    }
    private static float GetParticleValue(PartSysEmitter emitter, int particleIdx, PartSysParamId paramId,
                                          float atLifetime, float defaultValue = 0.0f)
    {
        var state = emitter.GetParamState(paramId);

        return(state?.GetValue(emitter, particleIdx, atLifetime) ?? defaultValue);
    }
示例#3
0
    private static byte GetParticleColorComponent(ParticleStateField stateField,
                                                  PartSysParamId paramId,
                                                  PartSysEmitter emitter,
                                                  int particleIdx)
    {
        var  colorParam = emitter.GetParamState(paramId);
        byte value;

        if (colorParam != null)
        {
            var partAge   = emitter.GetParticleAge(particleIdx);
            var partColor = colorParam.GetValue(emitter, particleIdx, partAge);
            partColor += emitter.GetParticleState().GetState(stateField, particleIdx);
            if (partColor >= 255)
            {
                value = 255;
            }
            else if (partColor < 0)
            {
                value = 0;
            }
            else
            {
                value = (byte)partColor;
            }
        }
        else
        {
            value =
                (byte)emitter.GetParticleState().GetState(stateField, particleIdx);
        }

        return(value);
    }
示例#4
0
        public override float GetValue(PartSysEmitter emitter, int particleIdx, float lifetimeSec)
        {
            for (var i = 0; i < _frames.Length - 1; ++i)
            {
                var frame     = _frames[i];
                var nextFrame = _frames[i + 1];

                // Don't LERP if we're right on the frame border
                // (or in case of the first frame, possibly earlier)
                if (lifetimeSec <= frame.start)
                {
                    return(frame.value);
                }
                else if (lifetimeSec >= nextFrame.start)
                {
                    continue; // The lifetime is beyond the current keyframe gap
                }

                // The lifetime is between start of frame and start of nextFrame
                // So let's lerp the value.
                var timeSinceFrame = lifetimeSec - frame.start;
                return(frame.value + frame.deltaPerSec * timeSinceFrame);
            }

            // Return the value of the last frame since we seem to be beyond it
            return(_frames[^ 1].value);
    public override void Render(IGameViewport viewport, PartSysEmitter emitter)
    {
        if (!GetEmitterWorldMatrix(viewport, emitter, out var worldMatrix))
        {
            return;
        }

        _device.SetVertexShaderConstants(0, ref worldMatrix);
        _device.SetIndexBuffer(_indexBuffer);

        RenderParticles(emitter);
    }
    public static void SimulateParticleAging(PartSysEmitter emitter, float timeToSimulateSec)
    {
        var it   = emitter.NewIterator();
        var ages = emitter.GetParticles();

        while (it.HasNext())
        {
            var particleIdx = it.Next();
            ages[particleIdx] += timeToSimulateSec;
        }

        emitter.PruneExpiredParticles();
    }
    public QuadEmitterRenderState(RenderingDevice device, PartSysEmitter emitter) : base(device, emitter, false)
    {
        bufferBinding = new BufferBinding(device, material.Resource.VertexShader).Ref();

        var maxCount = emitter.GetSpec().GetMaxParticles();

        vertexBuffer =
            device.CreateEmptyVertexBuffer(SpriteVertex.Size * 4 * maxCount, debugName:"ParticlesQuadEmitter");

        bufferBinding.Resource
            .AddBuffer<SpriteVertex>(vertexBuffer, 0)
            .AddElement(VertexElementType.Float4, VertexElementSemantic.Position)
            .AddElement(VertexElementType.Color, VertexElementSemantic.Color)
            .AddElement(VertexElementType.Float2, VertexElementSemantic.TexCoord);
    }
示例#8
0
    public static PackedLinearColorA GetParticleColor(PartSysEmitter emitter, int particleIdx)
    {
        var red =
            GetParticleColorComponent(ParticleStateField.PSF_RED, PartSysParamId.part_red, emitter, particleIdx);
        var green =
            GetParticleColorComponent(ParticleStateField.PSF_GREEN, PartSysParamId.part_green, emitter,
                                      particleIdx);
        var blue =
            GetParticleColorComponent(ParticleStateField.PSF_BLUE, PartSysParamId.part_blue, emitter, particleIdx);
        var alpha =
            GetParticleColorComponent(ParticleStateField.PSF_ALPHA, PartSysParamId.part_alpha, emitter,
                                      particleIdx);

        return(new PackedLinearColorA(red, green, blue, alpha));
    }
    private void RenderParticles(PartSysEmitter emitter)
    {
        var it         = emitter.NewIterator();
        var totalCount = emitter.GetActiveCount();

        if (totalCount == 0)
        {
            return;
        }

        // Lazily initialize render state
        if (!emitter.HasRenderState())
        {
            emitter.SetRenderState(
                new QuadEmitterRenderState(_device, emitter));
        }

        var renderState = (QuadEmitterRenderState)emitter.GetRenderState();

        using var spriteMemory = MemoryPool.Rent(4 * totalCount);
        var sUpdateBuffer = spriteMemory.Memory.Span.Slice(0, 4 * totalCount);

        var i = 0;

        while (it.HasNext())
        {
            var particleIdx = it.Next();
            FillVertex(emitter, particleIdx, sUpdateBuffer, i);
            i += 4;
        }

        renderState.vertexBuffer.Resource.Update <SpriteVertex>(sUpdateBuffer);

        _device.SetMaterial(renderState.material);
        renderState.bufferBinding.Resource.Bind();

        // Draw the batch
        _device.DrawIndexed(PrimitiveType.TriangleList, 4 * totalCount, 6 * totalCount);
    }
示例#10
0
    public static Material CreateMaterial(RenderingDevice device,
                                          PartSysEmitter emitter,
                                          bool pointSprites)
    {
        var blendState = new BlendSpec();

        blendState.blendEnable = true;

        switch (emitter.GetSpec().GetBlendMode())
        {
        case PartSysBlendMode.Add:
            blendState.srcBlend  = BlendOperand.SrcAlpha;
            blendState.destBlend = BlendOperand.One;
            break;

        case PartSysBlendMode.Subtract:
            blendState.srcBlend  = BlendOperand.Zero;
            blendState.destBlend = BlendOperand.InvSrcAlpha;
            break;

        case PartSysBlendMode.Blend:
            blendState.srcBlend  = BlendOperand.SrcAlpha;
            blendState.destBlend = BlendOperand.InvSrcAlpha;
            break;

        case PartSysBlendMode.Multiply:
            blendState.srcBlend  = BlendOperand.Zero;
            blendState.destBlend = BlendOperand.SrcColor;
            break;

        default:
            break;
        }

        // Particles respect the depth buffer, but do not modify it
        DepthStencilSpec depthStencilState = new DepthStencilSpec();

        depthStencilState.depthEnable = true;
        depthStencilState.depthWrite  = false;
        RasterizerSpec rasterizerState = new RasterizerSpec();

        rasterizerState.cullMode = CullMode.None;


        var samplers = new List <MaterialSamplerSpec>();

        var shaderName  = "diffuse_only_ps";
        var textureName = emitter.GetSpec().GetTextureName();

        if (textureName.Length > 0)
        {
            var samplerState = new SamplerSpec
            {
                addressU  = TextureAddress.Clamp,
                addressV  = TextureAddress.Clamp,
                minFilter = TextureFilterType.Linear,
                magFilter = TextureFilterType.Linear,
                mipFilter = TextureFilterType.Linear
            };
            var texture = device.GetTextures().Resolve(textureName, true);
            samplers.Add(new MaterialSamplerSpec(texture, samplerState));
            shaderName = "textured_simple_ps";
        }

        using var pixelShader = device.GetShaders().LoadPixelShader(shaderName);

        var vsName = pointSprites ? "particles_points_vs" : "particles_quads_vs";

        using var vertexShader = device.GetShaders().LoadVertexShader(vsName);

        return(device.CreateMaterial(blendState, depthStencilState, rasterizerState,
                                     samplers.ToArray(), vertexShader, pixelShader));
    }
示例#11
0
 public GeneralEmitterRenderState(RenderingDevice device, PartSysEmitter emitter, bool pointSprites)
 {
     material = CreateMaterial(device, emitter, pointSprites).Ref();
 }
示例#12
0
    public static void SimulateParticleMovement(PartSysEmitter emitter, float timeToSimulateSecs)
    {
        var spec = emitter.GetSpec();

        // Used as a factor in integrating the acceleration to retroactively calculate
        // its influence on the particle position
        var accelIntegrationFactor = timeToSimulateSecs * timeToSimulateSecs * 0.5f;

        var state = emitter.GetParticleState();
        var it    = emitter.NewIterator();

        while (it.HasNext())
        {
            var particleIdx = it.Next();
            var particleAge = emitter.GetParticleAge(particleIdx);

            var valueSource = new ParticleValueSource(emitter, particleIdx, particleAge);

            var x = state.GetState(ParticleStateField.PSF_X, particleIdx);
            var y = state.GetState(ParticleStateField.PSF_Y, particleIdx);
            var z = state.GetState(ParticleStateField.PSF_Z, particleIdx);

            var velX = state.GetState(ParticleStateField.PSF_VEL_X, particleIdx);
            var velY = state.GetState(ParticleStateField.PSF_VEL_Y, particleIdx);
            var velZ = state.GetState(ParticleStateField.PSF_VEL_Z, particleIdx);

            // Calculate new position of particle based on velocity
            x += timeToSimulateSecs * velX;
            y += timeToSimulateSecs * velY;
            z += timeToSimulateSecs * velZ;

            // Apply acceleration to velocity (retroactively to position as well)
            float value;
            if (valueSource.GetValue(PartSysParamId.part_accel_X, out value))
            {
                x    += accelIntegrationFactor * value;
                velX += timeToSimulateSecs * value;
            }

            if (valueSource.GetValue(PartSysParamId.part_accel_Y, out value))
            {
                y    += accelIntegrationFactor * value;
                velY += timeToSimulateSecs * value;
            }

            if (valueSource.GetValue(PartSysParamId.part_accel_Z, out value))
            {
                z    += accelIntegrationFactor * value;
                velZ += timeToSimulateSecs * value;
            }

            /*
             *  Apply Velocity Var
             */
            if (spec.GetParticleVelocityCoordSys() == PartSysCoordSys.Polar)
            {
                if (spec.GetParticlePosCoordSys() != PartSysCoordSys.Polar)
                {
                    // Velocity is polar, positions are not . convert velocity
                    var azimuth = emitter.GetParamValue(PartSysParamId.part_velVariation_X, particleIdx,
                                                        particleAge);
                    var inclination = emitter.GetParamValue(PartSysParamId.part_velVariation_Y, particleIdx,
                                                            particleAge);
                    var radius = emitter.GetParamValue(PartSysParamId.part_velVariation_Z, particleIdx,
                                                       particleAge);

                    var cartesianVel = SphericalDegToCartesian(azimuth, inclination, radius);
                    x += cartesianVel.X * timeToSimulateSecs;
                    y += cartesianVel.Y * timeToSimulateSecs;
                    z += cartesianVel.Z * timeToSimulateSecs;
                }
                else
                {
                    // Modify the spherical coordinates of the particle directly
                    if (valueSource.GetValue(PartSysParamId.part_velVariation_X, out value))
                    {
                        ref var azimuth = ref state.GetStatePtr(ParticleStateField.PSF_POS_AZIMUTH, particleIdx);
                        azimuth += value * timeToSimulateSecs;
                    }

                    if (valueSource.GetValue(PartSysParamId.part_velVariation_Y, out value))
                    {
                        ref var inclination =
                            ref state.GetStatePtr(ParticleStateField.PSF_POS_INCLINATION, particleIdx);
                        inclination += value * timeToSimulateSecs;
                    }

                    if (valueSource.GetValue(PartSysParamId.part_velVariation_Z, out value))
                    {
                        ref var radius = ref state.GetStatePtr(ParticleStateField.PSF_POS_RADIUS, particleIdx);
                        radius += value * timeToSimulateSecs;
                    }
                }
示例#13
0
    public override void Render(IGameViewport viewport, PartSysEmitter emitter)
    {
        var it = emitter.NewIterator();

        var animParams = AnimatedModelParams.Default;

        animParams.rotation3d = true;

        // Lazily initialize render state
        if (!emitter.HasRenderState())
        {
            // Resolve the mesh filename
            var baseName = ResolveBasename(emitter.GetSpec().GetMeshName());
            var skmName  = baseName + ".skm";
            var skaName  = baseName + ".ska";

            try
            {
                var animId = new EncodedAnimId(NormalAnimType.ItemIdle); // This seems to be item_idle
                var model  = _modelFactory.FromFilenames(skmName, skaName, animId, animParams);

                emitter.SetRenderState(
                    new ModelEmitterRenderState(model)
                    );
            }
            catch (Exception e)
            {
                Logger.Error("Unable to load model {0} for particle system {1}: {2}",
                             baseName, emitter.GetSpec().GetParent().GetName(), e);

                emitter.SetRenderState(new ModelEmitterRenderState(null));
            }
        }

        var renderState = (ModelEmitterRenderState)emitter.GetRenderState();

        if (renderState.Model == null)
        {
            return; // The loader above was unable to load the model for this emitter
        }

        var overrides = new MdfRenderOverrides
        {
            ignoreLighting  = true,
            overrideDiffuse = true
        };

        var yaw   = emitter.GetParamState(PartSysParamId.part_yaw);
        var pitch = emitter.GetParamState(PartSysParamId.part_pitch);
        var roll  = emitter.GetParamState(PartSysParamId.part_roll);

        while (it.HasNext())
        {
            var particleIdx = it.Next();
            var age         = emitter.GetParticleAge(particleIdx);

            overrides.overrideColor = GeneralEmitterRenderState.GetParticleColor(emitter, particleIdx);

            // Yes, this is *actually* swapped for Y / Z
            var particleState = emitter.GetParticleState();
            animParams.offsetX = particleState.GetState(ParticleStateField.PSF_POS_VAR_X, particleIdx);
            animParams.offsetY = particleState.GetState(ParticleStateField.PSF_POS_VAR_Z, particleIdx);
            animParams.offsetZ = particleState.GetState(ParticleStateField.PSF_POS_VAR_Y, particleIdx);

            if (yaw != null)
            {
                animParams.rotationYaw = Angles.ToRadians(yaw.GetValue(emitter, particleIdx, age));
            }

            if (pitch != null)
            {
                animParams.rotationPitch = Angles.ToRadians(pitch.GetValue(emitter, particleIdx, age));
            }

            if (roll != null)
            {
                animParams.rotationRoll = Angles.ToRadians(roll.GetValue(emitter, particleIdx, age));
            }

            renderState.Model.SetTime(animParams, age);

            _modelRenderer.Render(viewport, renderState.Model, animParams, new List <Light3d>(), overrides);
        }
    }
 protected abstract void FillVertex(PartSysEmitter emitter,
                                    int particleIdx,
                                    Span <SpriteVertex> vertices,
                                    int vertexIdx);
示例#15
0
    public static void SimulateParticleSpawn(IPartSysExternal external, PartSysEmitter emitter, int particleIdx,
                                             float timeToSimulate)
    {
        var spec          = emitter.GetSpec();
        var partSpawnTime = emitter.GetParticleSpawnTime(particleIdx);

        var worldPosVar = emitter.GetWorldPosVar();
        var particleX   = worldPosVar.X;
        var particleY   = worldPosVar.Y;
        var particleZ   = worldPosVar.Z;

        var emitOffsetX = GetParticleValue(emitter, particleIdx, PartSysParamId.emit_offset_X, partSpawnTime);
        var emitOffsetY = GetParticleValue(emitter, particleIdx, PartSysParamId.emit_offset_Y, partSpawnTime);
        var emitOffsetZ = GetParticleValue(emitter, particleIdx, PartSysParamId.emit_offset_Z, partSpawnTime);

        if (spec.GetOffsetCoordSys() == PartSysCoordSys.Polar)
        {
            var coords = SphericalDegToCartesian(emitOffsetX, emitOffsetY, emitOffsetZ);
            particleX += coords.X;
            particleY += coords.Y;
            particleZ += coords.Z;
        }
        else
        {
            particleX += emitOffsetX;
            particleY += emitOffsetY;
            particleZ += emitOffsetZ;
        }

        switch (spec.GetSpace())
        {
        case PartSysEmitterSpace.ObjectPos:
        case PartSysEmitterSpace.ObjectYpr:
        {
            if (spec.GetParticleSpace() != PartSysParticleSpace.SameAsEmitter)
            {
                // TODO: Figure out this formula...
                var scale      = 1.0f - emitter.GetParticleAge(particleIdx) / timeToSimulate;
                var prevObjPos = emitter.GetPrevObjPos();
                var objPos     = emitter.GetObjPos();
                var dX         = prevObjPos.X + (objPos.X - prevObjPos.X) * scale;
                var dY         = prevObjPos.Y + (objPos.Y - prevObjPos.Y) * scale;
                var dZ         = prevObjPos.Z + (objPos.Z - prevObjPos.Z) * scale;
                var rotation   = 0.0f;
                if (spec.GetSpace() == PartSysEmitterSpace.ObjectYpr)
                {
                    rotation = emitter.GetPrevObjRotation() +
                               (emitter.GetObjRotation() - emitter.GetPrevObjRotation()) * scale;
                }

                RotateAndMove(dX, dY, dZ, rotation, ref particleX, ref particleY, ref particleZ);
            }
        }
        break;

        case PartSysEmitterSpace.Bones:
        {
            var scale = 1.0f - emitter.GetParticleAge(particleIdx) / timeToSimulate;
            if (emitter.GetBoneState() == null)
            {
                break;
            }

            if (emitter.GetBoneState().GetRandomPos(scale, out var bonePos))
            {
                particleX = bonePos.X;
                particleY = bonePos.Y;
                particleZ = bonePos.Z;
            }
        }
        break;

        case PartSysEmitterSpace.NodePos:
        case PartSysEmitterSpace.NodeYpr:
        {
            if (spec.GetParticleSpace() != PartSysParticleSpace.SameAsEmitter)
            {
                var scale = 1.0f - emitter.GetParticleAge(particleIdx) / timeToSimulate;
                if (spec.GetSpace() == PartSysEmitterSpace.NodeYpr)
                {
                    if (!external.GetBoneWorldMatrix(emitter.GetAttachedTo(), spec.GetNodeName(),
                                                     out var boneM))
                    {
                        boneM = Matrix4x4.Identity;
                    }

                    var ppos   = new Vector3(particleX, particleY, particleZ);
                    var newpos = Vector3.Transform(ppos, boneM);
                    particleX = newpos.X;
                    particleY = newpos.Y;
                    particleZ = newpos.Z;
                }
                else
                {
                    var prevObjPos = emitter.GetPrevObjPos();
                    var objPos     = emitter.GetObjPos();
                    var dX         = prevObjPos.X + (objPos.X - prevObjPos.X) * scale;
                    var dY         = prevObjPos.Y + (objPos.Y - prevObjPos.Y) * scale;
                    var dZ         = prevObjPos.Z + (objPos.Z - prevObjPos.Z) * scale;
                    RotateAndMove(dX, dY, dZ, 0.0f, ref particleX, ref particleY, ref particleZ);
                }
            }
        }
        break;

        default:
            break;
        }

        var state = emitter.GetParticleState();

        state.SetState(ParticleStateField.PSF_X, particleIdx, particleX);
        state.SetState(ParticleStateField.PSF_Y, particleIdx, particleY);
        state.SetState(ParticleStateField.PSF_Z, particleIdx, particleZ);

        // Initialize particle color
        SetParticleParam(emitter, particleIdx, PartSysParamId.emit_init_red, partSpawnTime,
                         ParticleStateField.PSF_RED, 255.0f);
        SetParticleParam(emitter, particleIdx, PartSysParamId.emit_init_green, partSpawnTime,
                         ParticleStateField.PSF_GREEN, 255.0f);
        SetParticleParam(emitter, particleIdx, PartSysParamId.emit_init_blue, partSpawnTime,
                         ParticleStateField.PSF_BLUE, 255.0f);
        SetParticleParam(emitter, particleIdx, PartSysParamId.emit_init_alpha, partSpawnTime,
                         ParticleStateField.PSF_ALPHA, 255.0f);

        // Initialize particle velocity
        var partVelX = GetParticleValue(emitter, particleIdx, PartSysParamId.emit_init_vel_X, partSpawnTime);
        var partVelY = GetParticleValue(emitter, particleIdx, PartSysParamId.emit_init_vel_Y, partSpawnTime);
        var partVelZ = GetParticleValue(emitter, particleIdx, PartSysParamId.emit_init_vel_Z, partSpawnTime);

        if (spec.GetSpace() == PartSysEmitterSpace.ObjectYpr)
        {
            if (spec.GetParticleSpace() != PartSysParticleSpace.SameAsEmitter)
            {
                var scale = 1.0f - emitter.GetParticleAge(particleIdx) / timeToSimulate;

                var rotation = 0.0f;
                if (spec.GetSpace() == PartSysEmitterSpace.ObjectYpr)
                {
                    rotation = (emitter.GetObjRotation() - emitter.GetPrevObjRotation()) * scale +
                               emitter.GetPrevObjRotation();
                }

                // Rotate the velocity vector according to the current object rotation in the world
                // TODO: Even for rotation == 0, this will flip the velocity vector
                Rotate2D(rotation, ref partVelX, ref partVelZ);
            }
        }
        else if (spec.GetSpace() == PartSysEmitterSpace.NodeYpr)
        {
            if (spec.GetParticleSpace() != PartSysParticleSpace.SameAsEmitter)
            {
                var objId = emitter.GetAttachedTo();

                if (!external.GetBoneWorldMatrix(objId, spec.GetNodeName(), out var boneMatrix))
                {
                    boneMatrix = Matrix4x4.Identity;
                }

                // Construct a directional vector (not a positional one, w=0 here) for the velocity
                var dirVec = new Vector3(partVelX, partVelY, partVelZ);
                dirVec = Vector3.TransformNormal(dirVec, boneMatrix);

                partVelX = dirVec.X;
                partVelY = dirVec.Y;
                partVelZ = dirVec.Z;
            }
        }

        // Are particle coordinates defined as polar coordinates? Convert them to cartesian here
        if (spec.GetParticleVelocityCoordSys() == PartSysCoordSys.Polar)
        {
            var cartesianVel = SphericalDegToCartesian(partVelX, partVelY, partVelZ);
            partVelX = cartesianVel.X;
            partVelY = cartesianVel.Y;
            partVelZ = cartesianVel.Z;
        }

        state.SetState(ParticleStateField.PSF_VEL_X, particleIdx, partVelX);
        state.SetState(ParticleStateField.PSF_VEL_Y, particleIdx, partVelY);
        state.SetState(ParticleStateField.PSF_VEL_Z, particleIdx, partVelZ);

        // I don't know why it's taken at lifetime 0.
        // TODO: Figure out if this actually *never* changes?
        var posVarX = GetParticleValue(emitter, particleIdx, PartSysParamId.part_posVariation_X, 0);
        var posVarY = GetParticleValue(emitter, particleIdx, PartSysParamId.part_posVariation_Y, 0);
        var posVarZ = GetParticleValue(emitter, particleIdx, PartSysParamId.part_posVariation_Z, 0);

        // For a polar system, convert these positions to cartesian to apply them to the
        // rendering position
        if (spec.GetParticlePosCoordSys() == PartSysCoordSys.Polar)
        {
            state.SetState(ParticleStateField.PSF_POS_AZIMUTH, particleIdx, 0);
            state.SetState(ParticleStateField.PSF_POS_INCLINATION, particleIdx, 0);
            state.SetState(ParticleStateField.PSF_POS_RADIUS, particleIdx, 0);

            // Convert to cartesian and add to the actual current particle position
            // As usual, x, y, z here are (azimuth, inclination, radius)
            var cartesianPos = SphericalDegToCartesian(posVarX, posVarY, posVarZ);
            posVarX = cartesianPos.X;
            posVarY = cartesianPos.Y;
            posVarZ = cartesianPos.Z;
        }

        // Apply the position variation to the initial position and store it
        posVarX += particleX;
        posVarY += particleY;
        posVarZ += particleZ;
        state.SetState(ParticleStateField.PSF_POS_VAR_X, particleIdx, posVarX);
        state.SetState(ParticleStateField.PSF_POS_VAR_Y, particleIdx, posVarY);
        state.SetState(ParticleStateField.PSF_POS_VAR_Z, particleIdx, posVarZ);

        /*
         * The following code will apply particle movement after
         * spawning a particle retroactively. This should only happen
         * for high frequency particle systems that spawn multiple particles
         * per frame.
         * Also note how particle age instead of particle lifetime is used here
         * to access parameters of the emitter.
         */
        var partAge = emitter.GetParticleAge(particleIdx);

        if (partAge != 0)
        {
            var partAgeSquared = partAge * partAge;

            particleX += partVelX * partAge;
            particleY += partVelY * partAge;
            particleZ += partVelZ * partAge;

            var param = emitter.GetParamState(PartSysParamId.part_accel_X);
            if (param != null)
            {
                var accelX = param.GetValue(emitter, particleIdx, partAge);
                particleX += accelX * partAgeSquared * 0.5f;
                partVelX  += accelX * partAge;
            }

            param = emitter.GetParamState(PartSysParamId.part_accel_Y);
            if (param != null)
            {
                var accelY = param.GetValue(emitter, particleIdx, partAge);
                particleY += accelY * partAgeSquared * 0.5f;
                partVelY  += accelY * partAge;
            }

            param = emitter.GetParamState(PartSysParamId.part_accel_Z);
            if (param != null)
            {
                var accelZ = param.GetValue(emitter, particleIdx, partAge);
                particleZ += accelZ * partAgeSquared * 0.5f;
                partVelZ  += accelZ * partAge;
            }

            state.SetState(ParticleStateField.PSF_VEL_X, particleIdx, partVelX);
            state.SetState(ParticleStateField.PSF_VEL_Y, particleIdx, partVelY);
            state.SetState(ParticleStateField.PSF_VEL_Z, particleIdx, partVelZ);

            param = emitter.GetParamState(PartSysParamId.part_velVariation_X);
            if (param != null)
            {
                particleX += param.GetValue(emitter, particleIdx, partAge) * partAge;
            }

            param = emitter.GetParamState(PartSysParamId.part_velVariation_Y);
            if (param != null)
            {
                particleY += param.GetValue(emitter, particleIdx, partAge) * partAge;
            }

            param = emitter.GetParamState(PartSysParamId.part_velVariation_Z);
            if (param != null)
            {
                particleZ += param.GetValue(emitter, particleIdx, partAge) * partAge;
            }

            state.SetState(ParticleStateField.PSF_X, particleIdx, particleX);
            state.SetState(ParticleStateField.PSF_Y, particleIdx, particleY);
            state.SetState(ParticleStateField.PSF_Z, particleIdx, particleZ);
        }

        // Simulate rotation for anything other than a point particle
        if (spec.GetParticleType() != PartSysParticleType.Point)
        {
            var emitterAge = emitter.GetParticleSpawnTime(particleIdx);
            var rotation   = emitter.GetParamValue(PartSysParamId.emit_yaw, particleIdx, emitterAge, 0.0f);
            emitter.GetParticleState().SetState(ParticleStateField.PSF_ROTATION, particleIdx, rotation);
        }
    }
示例#16
0
 public abstract float GetValue(PartSysEmitter emitter, int particleIdx, float lifetimeSec);
示例#17
0
 public ParticleValueSource(PartSysEmitter emitter, int particleIdx, float particleAge)
 {
     this.emitter     = emitter;
     this.particleIdx = particleIdx;
     this.particleAge = particleAge;
 }
示例#18
0
    protected override void FillVertex(PartSysEmitter emitter,
                                       int particleIdx,
                                       Span <SpriteVertex> vertices,
                                       int vertexIdx)
    {
        // Calculate the particle scale (default is 1)
        var scale      = 1.0f;
        var scaleParam = emitter.GetParamState(PartSysParamId.part_scale_X);

        if (scaleParam != null)
        {
            scale = scaleParam.GetValue(emitter, particleIdx,
                                        emitter.GetParticleAge(particleIdx));
        }

        Vector4 halfPartHeightX;
        Vector4 halfPartHeightY;
        var     rotationParam = emitter.GetParamState(PartSysParamId.part_yaw);

        if (rotationParam != null)
        {
            var rotation = rotationParam.GetValue(
                emitter, particleIdx, emitter.GetParticleAge(particleIdx));
            rotation += emitter.GetParticleState().GetState(ParticleStateField.PSF_ROTATION, particleIdx);
            rotation  = Angles.ToRadians(rotation);

            var cosRot = MathF.Cos(rotation) * scale;
            var sinRot = MathF.Sin(rotation) * scale;
            halfPartHeightX = screenSpaceUnitX * cosRot - screenSpaceUnitY * sinRot;
            halfPartHeightY = screenSpaceUnitY * cosRot + screenSpaceUnitX * sinRot;
        }
        else
        {
            halfPartHeightX = screenSpaceUnitX * scale;
            halfPartHeightY = screenSpaceUnitY * scale;
        }

        var partPos = new Vector4(
            emitter.GetParticleState().GetState(ParticleStateField.PSF_POS_VAR_X, particleIdx),
            emitter.GetParticleState().GetState(ParticleStateField.PSF_POS_VAR_Y, particleIdx),
            emitter.GetParticleState().GetState(ParticleStateField.PSF_POS_VAR_Z, particleIdx),
            1
            );

        // Upper left corner
        vertices[vertexIdx + 0].pos = partPos - halfPartHeightX + halfPartHeightY;
        // Upper right corner
        vertices[vertexIdx + 1].pos = partPos + halfPartHeightX + halfPartHeightY;
        // Lower right corner
        vertices[vertexIdx + 2].pos = partPos + halfPartHeightX - halfPartHeightY;
        // Lower left corner
        vertices[vertexIdx + 3].pos = partPos - halfPartHeightX - halfPartHeightY;

        // Set the diffuse color for all corners
        var diffuse = GeneralEmitterRenderState.GetParticleColor(emitter, particleIdx);

        vertices[vertexIdx + 0].diffuse = diffuse;
        vertices[vertexIdx + 1].diffuse = diffuse;
        vertices[vertexIdx + 2].diffuse = diffuse;
        vertices[vertexIdx + 3].diffuse = diffuse;

        // Set UV coordinates for the sprite. We need to do this every frame
        // because we're using DISCARD for locking
        vertices[vertexIdx + 0].u = 0;
        vertices[vertexIdx + 0].v = 1;
        vertices[vertexIdx + 1].u = 1;
        vertices[vertexIdx + 1].v = 1;
        vertices[vertexIdx + 2].u = 1;
        vertices[vertexIdx + 2].v = 0;
        vertices[vertexIdx + 3].u = 0;
        vertices[vertexIdx + 3].v = 0;
    }
    protected bool GetEmitterWorldMatrix(IGameViewport viewport, PartSysEmitter emitter, out Matrix4x4 worldMatrix)
    {
        worldMatrix = Matrix4x4.Identity;

        var spec          = emitter.GetSpec();
        var particleSpace = spec.GetParticleSpace();
        var emitterSpace  = spec.GetSpace();

        if (particleSpace == PartSysParticleSpace.SameAsEmitter)
        {
            if (emitterSpace == PartSysEmitterSpace.ObjectPos || emitterSpace == PartSysEmitterSpace.ObjectYpr)
            {
                Matrix4x4 localMat;
                if (emitterSpace == PartSysEmitterSpace.ObjectYpr)
                {
                    var angle = emitter.GetObjRotation() + MathF.PI;
                    localMat = Matrix4x4.CreateRotationY(angle);
                }
                else
                {
                    localMat = Matrix4x4.Identity;
                }

                // Set the translation component of the transformation matrix
                localMat.Translation = emitter.GetObjPos();

                worldMatrix = localMat * viewport.Camera.GetViewProj();
                ExtractScreenSpaceUnitVectors(worldMatrix);
                return(true);
            }

            if (emitterSpace == PartSysEmitterSpace.NodePos || emitterSpace == PartSysEmitterSpace.NodeYpr)
            {
                var external = emitter.External;

                Matrix4x4 boneMatrix;
                if (emitterSpace == PartSysEmitterSpace.NodeYpr)
                {
                    if (!external.GetBoneWorldMatrix(emitter.GetAttachedTo(), spec.GetNodeName(), out boneMatrix))
                    {
                        // This effectively acts as a fallback if the bone doesn't exist
                        boneMatrix = Matrix4x4.CreateTranslation(emitter.GetObjPos());
                    }

                    worldMatrix = boneMatrix * viewport.Camera.GetViewProj();
                    ExtractScreenSpaceUnitVectors(worldMatrix);
                    return(true);
                }

                if (external.GetBoneWorldMatrix(emitter.GetAttachedTo(), spec.GetNodeName(), out boneMatrix))
                {
                    worldMatrix = Matrix4x4.CreateTranslation(boneMatrix.Translation) *
                                  viewport.Camera.GetViewProj();
                    ExtractScreenSpaceUnitVectors(worldMatrix);
                    return(true);
                }

                return(false);
            }

            worldMatrix = viewport.Camera.GetViewProj();
            ExtractScreenSpaceUnitVectors(worldMatrix);
            return(true);
        }

        if (particleSpace == PartSysParticleSpace.World)
        {
            worldMatrix = viewport.Camera.GetViewProj();
            ExtractScreenSpaceUnitVectors(worldMatrix);
            return(true);
        }

        if (emitterSpace != PartSysEmitterSpace.ObjectPos && emitterSpace != PartSysEmitterSpace.ObjectYpr)
        {
            if (emitterSpace != PartSysEmitterSpace.NodePos && emitterSpace != PartSysEmitterSpace.NodeYpr)
            {
                return(true);
            }

            var external = emitter.External;

            Matrix4x4 boneMatrix;
            if (emitterSpace == PartSysEmitterSpace.NodeYpr)
            {
                // Use the entire bone matrix if possible
                external.GetBoneWorldMatrix(emitter.GetAttachedTo(), spec.GetNodeName(), out boneMatrix);
            }
            else
            {
                // Only use the bone translation part
                if (!external.GetBoneWorldMatrix(emitter.GetAttachedTo(), spec.GetNodeName(), out boneMatrix))
                {
                    return(false);
                }
                boneMatrix =
                    Matrix4x4.CreateTranslation(boneMatrix.Translation); // TODO: This might not be needed...
            }

            worldMatrix = viewport.Camera.GetViewProj();
            ExtractScreenSpaceUnitVectors2(boneMatrix);
            return(true);
        }

        Matrix4x4 matrix;

        if (emitterSpace == PartSysEmitterSpace.ObjectYpr)
        {
            var angle = emitter.GetObjRotation() + MathF.PI;
            matrix = Matrix4x4.CreateRotationY(angle);
        }
        else
        {
            matrix = Matrix4x4.Identity;
        }

        worldMatrix = viewport.Camera.GetViewProj();
        ExtractScreenSpaceUnitVectors2(matrix);
        return(true);
    }
 public abstract void Render(IGameViewport viewport, PartSysEmitter emitter);