NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

particleSystemValidation.py (10261B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\evegraphics\validation\validators\particleSystemValidation.py
      2 import blue
      3 import trinity
      4 from trinity import effects, particlesystemelements
      5 from evegraphics.validation.commonUtilities import Validate, DeleteAction
      6 from evegraphics.validation.validators.effectValidation import effectCache
      7 
      8 @Validate('Tr2DynamicEmitter')
      9 def RateIsValid(context, emitter):
     10     if not context.IsBoundAsDestination(emitter, 'rate') and emitter.rate <= 0:
     11         context.Error(emitter, 'rate needs to be positive')
     12 
     13 
     14 @Validate('Tr2DynamicEmitter')
     15 def MaxParticlesIsValid(context, emitter):
     16     if not context.IsBoundAsDestination(emitter, 'maxParticles') and emitter.maxParticles == 0:
     17         context.Error(emitter, 'maxParticles is zero - emitter will not emit')
     18 
     19 
     20 @Validate('Tr2DynamicEmitter')
     21 def HasParticleSystem(context, emitter):
     22     if not emitter.particleSystem:
     23         context.Error(emitter, 'emitter is not attached to a particle system')
     24 
     25 
     26 @Validate('Tr2DynamicEmitter')
     27 def DynamicEmitterIsValid(context, emitter):
     28     if not emitter.isValid:
     29         context.Error(emitter, 'emitter reports as being invalid')
     30 
     31 
     32 @Validate('EveChildParticleSphere')
     33 def ParticleSphereIsValid(context, sphere):
     34     if not sphere.isValid:
     35         context.Error(sphere, 'particle sphere reports as being invalid')
     36 
     37 
     38 @Validate('Tr2DynamicEmitter')
     39 def ConstantParticleSystemBoundToDynamicEmitter(context, emitter):
     40     if emitter.particleSystem:
     41         if not emitter.particleSystem.updateSimulation:
     42             context.Error(emitter, 'dynamic emitter emits into a constant particle system (particle system updateSimulation flag is off)')
     43 
     44 
     45 @Validate('Tr2ParticleSystem')
     46 def ParticleSystemIsValid(context, particleSystem):
     47     if not particleSystem.isValid:
     48         context.Error(particleSystem, 'particle system reports as being invalid')
     49 
     50 
     51 @Validate('Tr2ParticleSystem')
     52 def ConstantParticleSystemBoundToDynamicEmitter(context, particleSystem):
     53     if particleSystem.forces and not particleSystem.applyForce:
     54         context.Error(particleSystem, 'particle system has forces yet applyForce flag is off')
     55 
     56 
     57 @Validate('/*')
     58 def ParticleSystemsUsed(context, root):
     59     systems = set(blue.FindInterface(root, 'Tr2ParticleSystem'))
     60     for each in list(systems):
     61         if each.emitParticleOnDeathEmitter:
     62             try:
     63                 systems.remove(each)
     64             except KeyError:
     65                 pass
     66 
     67         if each.emitParticleDuringLifeEmitter:
     68             try:
     69                 systems.remove(each)
     70             except KeyError:
     71                 pass
     72 
     73     for each in blue.FindInterface(root, 'Tr2InstancedMesh'):
     74         if each.instanceGeometryResource in systems:
     75             systems.remove(each.instanceGeometryResource)
     76 
     77     for each in systems:
     78         context.Error(each, 'system is not used', actions=[DeleteAction(context.GetStack()[0], each, True)])
     79 
     80 
     81 @Validate('/*')
     82 def ParticleSystemsHaveEmitters(context, root):
     83     systems = set(blue.FindInterface(root, 'Tr2ParticleSystem'))
     84     emitters = blue.FindInterface(root, 'Tr2DynamicEmitter') + blue.FindInterface(root, 'Tr2StaticEmitter') + blue.FindInterface(root, 'EveChildParticleSphere')
     85     for each in list(systems):
     86         if each.emitParticleOnDeathEmitter in systems:
     87             systems.remove(each.emitParticleOnDeathEmitter)
     88         if each.emitParticleDuringLifeEmitter in systems:
     89             systems.remove(each.emitParticleDuringLifeEmitter)
     90 
     91     for each in emitters:
     92         if each.particleSystem in systems:
     93             systems.remove(each.particleSystem)
     94 
     95     for each in systems:
     96         context.Error(each, 'there are no emitters emitting into this particle system', actions=[DeleteAction(context.GetStack()[0], each, True)])
     97 
     98 
     99 def _UnsetUsedByGpu(element, particleSystem, root, default):
    100 
    101     def inner():
    102         element.usedByGPU = False
    103         particleSystem.UpdateElementDeclaration()
    104         emitters = blue.FindInterface(root, 'Tr2DynamicEmitter')
    105         for each in emitters:
    106             if each.particleSystem == particleSystem:
    107                 each.Rebind()
    108 
    109         for each in blue.FindInterface(root, 'Tr2InstancedMesh'):
    110             if each.instanceGeometryResource == particleSystem:
    111                 each.instanceGeometryResource = None
    112                 each.instanceGeometryResource = particleSystem
    113 
    114         return True
    115 
    116     return ('Unset usedByGPU flag', inner, default)
    117 
    118 
    119 def _DeleteElement(element, particleSystem, root, default):
    120 
    121     def inner():
    122         particleSystem.elements.remove(element)
    123         particleSystem.UpdateElementDeclaration()
    124         particleSystem.RebindConstraints()
    125         emitters = blue.FindInterface(root, 'Tr2DynamicEmitter') + blue.FindInterface(root, 'EveChildParticleSphere')
    126         for each in emitters:
    127             if each.particleSystem == particleSystem:
    128                 for generator in each.generators:
    129                     if isinstance(generator, trinity.Tr2SphereShapeAttributeGenerator):
    130                         if element.elementType == trinity.PARTICLE_ELEMENT_TYPE.POSITION:
    131                             generator.controlPosition = False
    132                             break
    133                         elif element.elementType == trinity.PARTICLE_ELEMENT_TYPE.VELOCITY:
    134                             generator.controlVelocity = False
    135                             break
    136                     elif generator.elementType == element.elementType:
    137                         if element.elementType != trinity.PARTICLE_ELEMENT_TYPE.CUSTOM or generator.customName == element.customName:
    138                             each.generators.remove(generator)
    139                             break
    140 
    141                 if hasattr(each, 'Rebind'):
    142                     each.Rebind()
    143                 else:
    144                     each.Refresh()
    145 
    146         for each in blue.FindInterface(root, 'Tr2InstancedMesh'):
    147             if each.instanceGeometryResource == particleSystem:
    148                 each.instanceGeometryResource = None
    149                 each.instanceGeometryResource = particleSystem
    150 
    151         return True
    152 
    153     return ('Delete element', inner, default)
    154 
    155 
    156 def _CheckShaderInputs(context, inputs, particleSystem, elementNames):
    157     psToVs = {trinity.PARTICLE_ELEMENT_TYPE.LIFETIME: 3,
    158      trinity.PARTICLE_ELEMENT_TYPE.POSITION: 0,
    159      trinity.PARTICLE_ELEMENT_TYPE.VELOCITY: 2,
    160      trinity.PARTICLE_ELEMENT_TYPE.MASS: 4,
    161      trinity.PARTICLE_ELEMENT_TYPE.CUSTOM: 5}
    162     vsToPs = {v:k for k, v in psToVs.items()}
    163     for each in particleSystem.elements:
    164         usage = psToVs[each.elementType]
    165         usageIndex = 8 if each.elementType == 1 else each.usageIndex + 8
    166         if (usage, usageIndex) in inputs:
    167             inputs.remove((usage, usageIndex))
    168         elif each.usedByGPU:
    169             isCustom = each.elementType == trinity.PARTICLE_ELEMENT_TYPE.CUSTOM
    170             actions = [_UnsetUsedByGpu(each, particleSystem, context.GetStack()[0], not isCustom)]
    171             if each.elementType not in [trinity.PARTICLE_ELEMENT_TYPE.POSITION, trinity.PARTICLE_ELEMENT_TYPE.VELOCITY, trinity.PARTICLE_ELEMENT_TYPE.LIFETIME]:
    172                 actions.append(_DeleteElement(each, particleSystem, context.GetStack()[0], isCustom))
    173             context.Error(each, 'element has usedByGPU set, but the shader does not use it', actions=actions)
    174 
    175     for usage, usageIndex in inputs:
    176         if usageIndex < 8:
    177             continue
    178         if usage in vsToPs:
    179             try:
    180                 name = elementNames[vsToPs[usage], usageIndex - 8]
    181             except KeyError:
    182                 name = trinity.PARTICLE_ELEMENT_TYPE.GetNameFromValue(vsToPs[usage])
    183                 if vsToPs[usage] == trinity.PARTICLE_ELEMENT_TYPE.CUSTOM:
    184                     name += '/%s' % (usageIndex - 8)
    185 
    186         else:
    187             name = '(%s, %s)' % (usage, usageIndex - 8)
    188         context.Error(particleSystem, 'the shader expects an %s element that is not present in the particle system' % name)
    189 
    190 
    191 @Validate('/*')
    192 def CheckShaderInputs(context, root):
    193     ps = {}
    194     elementNames = {}
    195     for mesh in blue.FindInterface(root, 'Tr2InstancedMesh'):
    196         if isinstance(mesh.instanceGeometryResource, trinity.Tr2ParticleSystem):
    197             areas = []
    198             if mesh.opaqueAreas:
    199                 areas.extend(mesh.opaqueAreas)
    200             if mesh.decalAreas:
    201                 areas.extend(mesh.decalAreas)
    202             if mesh.depthAreas:
    203                 areas.extend(mesh.depthAreas)
    204             if mesh.transparentAreas:
    205                 areas.extend(mesh.transparentAreas)
    206             if mesh.additiveAreas:
    207                 areas.extend(mesh.additiveAreas)
    208             if mesh.pickableAreas:
    209                 areas.extend(mesh.pickableAreas)
    210             if mesh.mirrorAreas:
    211                 areas.extend(mesh.mirrorAreas)
    212             if mesh.decalNormalAreas:
    213                 areas.extend(mesh.decalNormalAreas)
    214             if mesh.depthNormalAreas:
    215                 areas.extend(mesh.depthNormalAreas)
    216             if mesh.opaquePrepassAreas:
    217                 areas.extend(mesh.opaquePrepassAreas)
    218             if mesh.decalPrepassAreas:
    219                 areas.extend(mesh.decalPrepassAreas)
    220             if mesh.geometryEraserAreas:
    221                 areas.extend(mesh.geometryEraserAreas)
    222             if mesh.distortionAreas:
    223                 areas.extend(mesh.distortionAreas)
    224             inputs = set()
    225             for each in areas:
    226                 if each.effect:
    227                     inputs.update(effects.GetVertexShaderInputs(each.effect, effectCache))
    228                     for k, v in particlesystemelements.GetParticleElementAnnotations(each.effect, effectCache).items():
    229                         if v.name:
    230                             elementNames[k] = v.name
    231 
    232             ps.setdefault(mesh.instanceGeometryResource, set()).update(inputs)
    233 
    234     for k, v in ps.items():
    235         _CheckShaderInputs(context, v, k, elementNames)
    236 
    237 
    238 @Validate('Tr2InstancedMesh')
    239 def NoCopyPasteBounds(context, mesh):
    240     if mesh.boundsMethod != trinity.Tr2InstanceMeshBoundsMethod.STATIC:
    241         return
    242     if mesh.minBounds == (-10000000000.0, -10000000000.0, -10000000000.0) or mesh.maxBounds == (10000000000.0, 10000000000.0, 10000000000.0):
    243         context.Error(mesh, 'invalid mesh bounds (copy-paste error?)')