From d73d86ce11c135734574a3d4b51f5ca76c69458b Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Mon, 19 Jul 2021 18:36:41 +0200 Subject: [PATCH] Keep hold of surface flag when converting brush model surfaces, and use this to identify liquid surfaces during material creation. Liquids now have their own material with the option to apply alpha blending depending on the type of liquid. Also includes some first bits of particle systems. Not actually used yet. --- Assets/Scripts/Data/QModel.cs | 23 ++- Assets/Scripts/Game/GameState.cs | 4 +- Assets/Scripts/Support/BrushModel.cs | 15 +- Assets/Scripts/VisualStyle.cs | 56 +++++++- Assets/Styles/GLQuake/GLQuake.asset | 8 ++ .../GLQuake/Materials/GLQuake_Liquid.mat | 135 ++++++++++++++++++ .../GLQuake/Materials/GLQuake_Liquid.mat.meta | 8 ++ .../GLQuake/Materials/GLQuake_World.mat | 6 + 8 files changed, 245 insertions(+), 10 deletions(-) create mode 100644 Assets/Styles/GLQuake/Materials/GLQuake_Liquid.mat create mode 100644 Assets/Styles/GLQuake/Materials/GLQuake_Liquid.mat.meta diff --git a/Assets/Scripts/Data/QModel.cs b/Assets/Scripts/Data/QModel.cs index e20c332..d3f7310 100644 --- a/Assets/Scripts/Data/QModel.cs +++ b/Assets/Scripts/Data/QModel.cs @@ -281,7 +281,7 @@ public struct QSurface public QVec3 mins, maxs; public IntPtr plane; // Pointer to mplane_t - public int flags; + public QSurfaceFlags flags; public int firstEdge; public int numEdges; @@ -355,3 +355,24 @@ public struct QTexInfo // This is safe as the Quake engine guarantees this pointer is never null (see: Mod_LoadTexinfo) public QTexture Texture => Marshal.PtrToStructure(texture); } + +/// +/// Managed equivalent of SURF_ defines +/// +[Flags] +public enum QSurfaceFlags : int +{ + PlaneBack = 0x2, + DrawSky = 0x4, + DrawSprite = 0x8, + DrawTurbulence = 0x10, + DrawTiled = 0x20, + DrawBackground = 0x40, + Underwater = 0x80, + NoTexture = 0x100, + DrawFence = 0x200, + DrawLava = 0x400, + DrawSlime = 0x800, + DrawTeleporter = 0x1000, + DrawWater = 0x2000, +} diff --git a/Assets/Scripts/Game/GameState.cs b/Assets/Scripts/Game/GameState.cs index 25d1192..8eba75d 100644 --- a/Assets/Scripts/Game/GameState.cs +++ b/Assets/Scripts/Game/GameState.cs @@ -50,7 +50,9 @@ public class GameState // TODO FIXME This is wrong for brush model entities uq.CurrentStyle.SetupWorldRenderer(mr); - mr.material = uq.CurrentStyle.CreateWorldMaterial(); // TODO FIXME this currently leaks Materials + mr.material = surfaceMesh.Flags.HasFlag(QSurfaceFlags.DrawTurbulence) + ? uq.CurrentStyle.CreateLiquidMaterial(surfaceMesh.Flags) + : uq.CurrentStyle.CreateWorldMaterial(); // TODO FIXME this currently leaks Materials uint texNum = surfaceMesh.TextureNum; if (uq.GameAssets.TryGetTexture(texNum, out var texture)) diff --git a/Assets/Scripts/Support/BrushModel.cs b/Assets/Scripts/Support/BrushModel.cs index cbb4658..b810c33 100644 --- a/Assets/Scripts/Support/BrushModel.cs +++ b/Assets/Scripts/Support/BrushModel.cs @@ -40,16 +40,16 @@ public class BrushModel // Traverse the BSP tree and group the surfaces based on their material properties var headNode = inSubModels[modelIdx].GetHeadNode(model); - var surfaceGroups = new Dictionary<(IntPtr, int), List>(); + var surfaceGroups = new Dictionary<(IntPtr, int, QSurfaceFlags), List>(); GroupSurfaces(headNode, inSurfaces, surfaceGroups); // Create a single mesh for each group of surfaces foreach (var group in surfaceGroups) { var key = group.Key; - var mesh = CreateMeshFromSurfaces(group.Value, $"T{key.Item1}_L{key.Item2}"); + var mesh = CreateMeshFromSurfaces(group.Value, $"T{key.Item1}_L{key.Item2}_F{(int)key.Item3}"); - subModel.AddSurfaceMesh(new SurfaceMesh(mesh, key.Item1, key.Item2)); + subModel.AddSurfaceMesh(new SurfaceMesh(mesh, key.Item1, key.Item2, key.Item3)); } } } @@ -64,7 +64,7 @@ public class BrushModel subModels.Clear(); } - private void GroupSurfaces(QNode node, QSurface[] surfaces, Dictionary<(IntPtr, int), List> surfaceGroups) + private void GroupSurfaces(QNode node, QSurface[] surfaces, Dictionary<(IntPtr, int, QSurfaceFlags), List> surfaceGroups) { if (node.contents < 0) // Leaf node return; @@ -75,7 +75,8 @@ public class BrushModel IntPtr texPtr = surface.TextureInfo.texture; int lightNum = surface.lightmapTextureNum; - var key = (texPtr, lightNum); + QSurfaceFlags flags = surface.flags; + var key = (texPtr, lightNum, flags); if (!surfaceGroups.ContainsKey(key)) surfaceGroups[key] = new List(); @@ -162,8 +163,9 @@ public class BrushModel public uint FullBrightNum { get; } public uint WarpImageNum { get; } public int Lightmap { get; } + public QSurfaceFlags Flags { get; } - public SurfaceMesh(Mesh mesh, IntPtr texturePtr, int lightmap) + public SurfaceMesh(Mesh mesh, IntPtr texturePtr, int lightmap, QSurfaceFlags flags) { Mesh = mesh; var texture = Marshal.PtrToStructure(texturePtr); @@ -171,6 +173,7 @@ public class BrushModel FullBrightNum = texture.FullBrightNum; WarpImageNum = texture.WarpImageNum; Lightmap = lightmap; + Flags = flags; } public void Dispose() diff --git a/Assets/Scripts/VisualStyle.cs b/Assets/Scripts/VisualStyle.cs index 21cf7ee..048f7c9 100644 --- a/Assets/Scripts/VisualStyle.cs +++ b/Assets/Scripts/VisualStyle.cs @@ -11,8 +11,16 @@ public class VisualStyle : ScriptableObject [SerializeField] protected Material worldMaterial; // TODO: split into wall, liquid, sky, etc - - // TODO: add particle effects + + [SerializeField] + protected Material liquidMaterial; + + [SerializeField] + protected LiquidProperties liquidProperties = new LiquidProperties(); + + [SerializeField] + protected ParticleSystems particles = new ParticleSystems(); + public ParticleSystems Particles => particles; public virtual Material CreateEntityMaterial() { @@ -23,6 +31,26 @@ public class VisualStyle : ScriptableObject { return new Material(worldMaterial); } + + public virtual Material CreateLiquidMaterial(QSurfaceFlags surfaceFlags) + { + if (liquidMaterial == null) + return CreateWorldMaterial(); + + float alpha = 1f; + if (surfaceFlags.HasFlag(QSurfaceFlags.DrawWater)) + alpha = liquidProperties.waterAlpha; + else if (surfaceFlags.HasFlag(QSurfaceFlags.DrawSlime)) + alpha = liquidProperties.slimeAlpha; + else if (surfaceFlags.HasFlag(QSurfaceFlags.DrawLava)) + alpha = liquidProperties.lavaAlpha; + else if (surfaceFlags.HasFlag(QSurfaceFlags.DrawTeleporter)) + alpha = liquidProperties.teleporterAlpha; + + var material = new Material(liquidMaterial); + material.SetColor("_BaseColor", new Color(1, 1, 1, alpha)); + return material; + } public virtual void SetupEntityRenderer(MeshRenderer meshRenderer) { @@ -76,3 +104,27 @@ public class VisualStyle : ScriptableObject // TODO: lightmap texture } } + +[System.Serializable] +public class LiquidProperties +{ + [Range(0, 1)] + public float + waterAlpha = 0.85f, + slimeAlpha = 0.9f, + lavaAlpha = 0.95f, + teleporterAlpha = 1.0f; +} + +[System.Serializable] +public class ParticleSystems +{ + [SerializeField] + protected ParticleSystem explosion; + + public virtual void CreateExplosion(Vector3 position) + { + var go = Object.Instantiate(explosion.gameObject); + go.transform.position = position; + } +} diff --git a/Assets/Styles/GLQuake/GLQuake.asset b/Assets/Styles/GLQuake/GLQuake.asset index a5495ac..ad7c1fd 100644 --- a/Assets/Styles/GLQuake/GLQuake.asset +++ b/Assets/Styles/GLQuake/GLQuake.asset @@ -14,3 +14,11 @@ MonoBehaviour: m_EditorClassIdentifier: entityMaterial: {fileID: 2100000, guid: 4d7703ac1adf3534f89b4041b779ff5e, type: 2} worldMaterial: {fileID: 2100000, guid: fcbaf32c00bea2344bbb1419c61364b6, type: 2} + liquidMaterial: {fileID: 2100000, guid: cd59502a1689c0847a1963c60e347987, type: 2} + liquidProperties: + waterAlpha: 0.85 + slimeAlpha: 0.9 + lavaAlpha: 0.95 + teleporterAlpha: 1 + particles: + explosion: {fileID: 0} diff --git a/Assets/Styles/GLQuake/Materials/GLQuake_Liquid.mat b/Assets/Styles/GLQuake/Materials/GLQuake_Liquid.mat new file mode 100644 index 0000000..b79d064 --- /dev/null +++ b/Assets/Styles/GLQuake/Materials/GLQuake_Liquid.mat @@ -0,0 +1,135 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-538773200983810463 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 4 +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: GLQuake_Liquid + m_Shader: {fileID: 4800000, guid: 8d2bb70cbf9db8d4da26e15b26e74248, type: 3} + m_ShaderKeywords: _EMISSION _RECEIVE_SHADOWS_OFF + m_LightmapFlags: 2 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: + - SHADOWCASTER + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ClearCoatMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _AlphaClip: 0 + - _Blend: 0 + - _BumpScale: 1 + - _ClearCoat: 0 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossinessSource: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 0 + - _SampleGI: 0 + - _Shininess: 0 + - _Smoothness: 0.5 + - _SmoothnessSource: 0 + - _SmoothnessTextureChannel: 0 + - _SpecSource: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 5 + - _Surface: 1 + - _WorkflowMode: 1 + - _ZWrite: 0 + m_Colors: + - _BaseColor: {r: 1, g: 1, b: 1, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 1, g: 1, b: 1, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Styles/GLQuake/Materials/GLQuake_Liquid.mat.meta b/Assets/Styles/GLQuake/Materials/GLQuake_Liquid.mat.meta new file mode 100644 index 0000000..cbc3841 --- /dev/null +++ b/Assets/Styles/GLQuake/Materials/GLQuake_Liquid.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cd59502a1689c0847a1963c60e347987 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Styles/GLQuake/Materials/GLQuake_World.mat b/Assets/Styles/GLQuake/Materials/GLQuake_World.mat index aed4ae6..f8f23a8 100644 --- a/Assets/Styles/GLQuake/Materials/GLQuake_World.mat +++ b/Assets/Styles/GLQuake/Materials/GLQuake_World.mat @@ -41,6 +41,10 @@ Material: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} + - _ClearCoatMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} - _DetailAlbedoMap: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} @@ -93,6 +97,7 @@ Material: - _AlphaClip: 0 - _Blend: 0 - _BumpScale: 1 + - _ClearCoat: 0 - _ClearCoatMask: 0 - _ClearCoatSmoothness: 0 - _Cull: 2 @@ -110,6 +115,7 @@ Material: - _Parallax: 0.005 - _QueueOffset: 0 - _ReceiveShadows: 0 + - _SampleGI: 0 - _Shininess: 0 - _Smoothness: 0.5 - _SmoothnessSource: 0