示例#1
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);
    }
    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);
    }
        public bool GetValue(PartSysParamId paramId, out float value)
        {
            var state = emitter.GetParamState(paramId);

            if (state != null)
            {
                value = state.GetValue(emitter, particleIdx, particleAge);
                return(true);
            }

            value = float.NaN;
            return(false);
        }
示例#4
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);
        }
    }
示例#5
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;
    }
    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);
        }
    }