Browse Source

Added entity lighting support, by forwarding the shade vector and light color from the engine to Unity. The lighting calculations are replicated in the Quake shader.

This is currently per-pixel shading (as opposed to the more authentic gouraud shading) and it's only applied to alias models at the moment. Brush models will have to be figured out properly.
readme
Nico de Poel 5 years ago
parent
commit
bd39eb57cc
  1. 10
      Assets/Scripts/Data/QExtensions.cs
  2. 9
      Assets/Scripts/Game/Entity.cs
  3. 15
      Assets/Scripts/Modules/GameModule.Interop.cs
  4. 5
      Assets/Scripts/Modules/GameModule.cs
  5. 3
      Assets/Shaders/Quake.shader
  6. 15
      Assets/Shaders/QuakeForwardPass.hlsl
  7. 6
      Assets/Shaders/QuakeInput.hlsl
  8. 1
      engine/Quake/client.h
  9. 2
      engine/Quake/r_alias.c
  10. 6
      engine/UniQuake/game_uniquake.c

10
Assets/Scripts/Data/QExtensions.cs

@ -55,6 +55,11 @@ public static class QExtensions
{
return new Vector3(origin.y, origin.z, -origin.x);
}
public static Vector3 ToUnityDirection(this QVec3 dir)
{
return new Vector3(dir.y, dir.z, -dir.x);
}
public static Quaternion ToUnityRotation(this QVec3 angles)
{
@ -71,4 +76,9 @@ public static class QExtensions
(byte)((color >> 16) & 0xFF),
(byte)((color >> 24) & 0xFF));
}
public static Color ToColor(this QVec3 vec)
{
return new Color(vec.x, vec.y, vec.z);
}
}

9
Assets/Scripts/Game/Entity.cs

@ -159,6 +159,15 @@ public class Entity
}
}
public void SetLighting(Vector3 shadeVector, Color lightColor)
{
if (material == null)
return;
material.SetVector("_ShadeVector", shadeVector);
material.SetVector("_LightColor", lightColor);
}
private void AssignMeshRenderer()
{
material = visualStyle.CreateEntityMaterial(true);

15
Assets/Scripts/Modules/GameModule.Interop.cs

@ -17,6 +17,7 @@ public partial class GameModule : CallbackHandler<GameModule>
RemoveEntity = CreateCallback<GameRemoveEntityCallback>(Callback_GameRemoveEntity),
UpdateEntityAnimation = CreateCallback<GameUpdateEntityAnimationCallback>(Callback_GameUpdateEntityAnimation),
SetEntitySkin = CreateCallback<GameSetEntitySkinCallback>(Callback_GameSetEntitySkin),
SetEntityLighting = CreateCallback<GameSetEntityLightingCallback>(Callback_GameSetEntityLighting),
RunParticleEffect = CreateCallback<RunParticleEffectCallback>(Callback_RunParticleEffect),
CreateParticleEffect = CreateCallback<CreateParticleEffectCallback>(Callback_CreateParticleEffect),
@ -37,6 +38,7 @@ public partial class GameModule : CallbackHandler<GameModule>
public IntPtr RemoveEntity;
public IntPtr UpdateEntityAnimation;
public IntPtr SetEntitySkin;
public IntPtr SetEntityLighting;
public IntPtr RunParticleEffect;
public IntPtr CreateParticleEffect;
@ -98,6 +100,17 @@ public partial class GameModule : CallbackHandler<GameModule>
Profiler.EndSample();
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void GameSetEntityLightingCallback(IntPtr context, int entityNum, ref QVec3 shadeVector, ref QVec3 lightColor);
[MonoPInvokeCallback(typeof(GameSetEntityLightingCallback))]
private static void Callback_GameSetEntityLighting(IntPtr context, int entityNum, ref QVec3 shadeVector, ref QVec3 lightColor)
{
Profiler.BeginSample("GameSetEntityLighting");
GetSelf(context).SetEntityLighting(entityNum, shadeVector.ToUnityDirection(), lightColor.ToColor());
Profiler.EndSample();
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void RunParticleEffectCallback(IntPtr context, ref QVec3 origin, ref QVec3 direction, uint colorMin, uint colorMax, int count);
@ -105,7 +118,7 @@ public partial class GameModule : CallbackHandler<GameModule>
private static void Callback_RunParticleEffect(IntPtr context, ref QVec3 origin, ref QVec3 direction, uint colorMin, uint colorMax, int count)
{
Profiler.BeginSample("RunParticleEffect");
GetSelf(context).RunParticleEffect(origin.ToUnityPosition(), direction.ToUnityPosition(), colorMin.ToColor(), colorMax.ToColor(), count);
GetSelf(context).RunParticleEffect(origin.ToUnityPosition(), direction.ToUnityDirection(), colorMin.ToColor(), colorMax.ToColor(), count);
Profiler.EndSample();
}

5
Assets/Scripts/Modules/GameModule.cs

@ -67,6 +67,11 @@ public partial class GameModule
{
uq.GameState.GetEntity(entityNum).SetSkin(skinNum);
}
private void SetEntityLighting(int entityNum, Vector3 shadeVector, Color lightColor)
{
uq.GameState.GetEntity(entityNum).SetLighting(shadeVector, lightColor);
}
private void RunParticleEffect(Vector3 position, Vector3 direction, Color colorMin, Color colorMax, int count)
{

3
Assets/Shaders/Quake.shader

@ -12,6 +12,9 @@ Shader "UniQuake/Quake"
[HDR] _EmissionColor("Emission Color", Color) = (0,0,0)
[NoScaleOffset]_EmissionMap("Emission Map", 2D) = "white" {}
[HideInInspector] _ShadeVector("Shade Vector", Vector) = (0, 0, 0)
[HideInInspector] _LightColor("Light Color", Color) = (1, 1, 1, 1)
// Blending state
[HideInInspector] _Surface("__surface", Float) = 0.0

15
Assets/Shaders/QuakeForwardPass.hlsl

@ -30,7 +30,7 @@ struct Varyings
float3 posWS : TEXCOORD2; // xyz: posWS
float3 normal : TEXCOORD3;
float3 normal : TEXCOORD3;
float3 viewDir : TEXCOORD4;
half4 fogFactorAndVertexLight : TEXCOORD6; // x: fogFactor, yzw: vertex light
@ -129,11 +129,14 @@ half4 LitPassFragmentSimple(Varyings input) : SV_Target
half4 lightmapColor = SAMPLE_TEXTURE2D(_LightMap, sampler_LightMap, input.lightmapUV);
half3 finalColor = diffuse * lightmapColor.rgb * 2.0f;
#else
// Specular and smoothness are some bogus values just to make models not appear completely black on one side
half3 finalColor = UniversalFragmentBlinnPhong(inputData, diffuse, half4(0.2, 0.2, 0.2, 1), 0.5, 0.0, alpha).rgb;
// Light light = GetMainLight();
// half3 diffuseColor = LightingLambert(light.color, light.direction, inputData.normalWS);
// half3 finalColor = diffuse * diffuseColor;
// This reproduces anorm_dots within a reasonable degree of tolerance
half shade = dot(_ShadeVector.xyz, inputData.normalWS);
if (shade < 0.0)
shade = 1.0 + shade * (13.0 / 44.0);
else
shade = 1.0 + shade;
half3 finalColor = diffuse * shade * _LightColor.rgb;
#endif
#ifdef _EMISSION

6
Assets/Shaders/QuakeInput.hlsl

@ -11,6 +11,8 @@ CBUFFER_START(UnityPerMaterial)
half4 _EmissionColor;
half _Cutoff;
half _Surface;
half4 _ShadeVector;
half4 _LightColor;
CBUFFER_END
#ifdef UNITY_DOTS_INSTANCING_ENABLED
@ -19,12 +21,16 @@ CBUFFER_END
UNITY_DOTS_INSTANCED_PROP(float4, _EmissionColor)
UNITY_DOTS_INSTANCED_PROP(float , _Cutoff)
UNITY_DOTS_INSTANCED_PROP(float , _Surface)
UNITY_DOTS_INSTANCED_PROP(half4, _ShadeVector)
UNITY_DOTS_INSTANCED_PROP(half4, _LightColor)
UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)
#define _BaseColor UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(float4 , Metadata__BaseColor)
#define _EmissionColor UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(float4 , Metadata__EmissionColor)
#define _Cutoff UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(float , Metadata__Cutoff)
#define _Surface UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(float , Metadata__Surface)
#define _ShadeVector UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(half4 , Metadata__ShadeVector)
#define _LightColor UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(half4 , Metadata__LightColor)
#endif
SAMPLER(point_repeat_sampler);

1
engine/Quake/client.h

@ -377,6 +377,7 @@ void UQ_Game_SetEntityTransform(int entityNum, vec3_t origin, vec3_t angles);
void UQ_Game_RemoveEntity(int entityNum);
void UQ_Game_UpdateEntityAnimation(int entityNum, int pose1, int pose2, float blend);
void UQ_Game_SetEntitySkin(int entityNum, int skinNum);
void UQ_Game_SetEntityLighting(int entityNum, vec3_t shadeVector, vec3_t lightColor);
#endif /* _CLIENT_H_ */

2
engine/Quake/r_alias.c

@ -619,6 +619,8 @@ void R_SetupAliasLighting (entity_t *e)
shadedots = r_avertexnormal_dots[quantizedangle];
VectorScale (lightcolor, 1.0f / 200.0f, lightcolor);
UQ_Game_SetEntityLighting(e->num, shadevector, lightcolor);
}
/*

6
engine/UniQuake/game_uniquake.c

@ -9,6 +9,7 @@ typedef struct unity_gamecalls_s
void(*RemoveEntity)(void *context, int entityNum);
void(*UpdateEntityAnimation)(void *context, int entityNum, int pose1, int pose2, float blend);
void(*SetEntitySkin)(void *context, int entityNum, int skinNum);
void(*SetEntityLighting)(void *context, int entityNum, vec3_t shadeVector, vec3_t lightColor);
void(*RunParticleEffect)(void *context, vec3_t origin, vec3_t direction, unsigned int colorMin, unsigned int colorMax, int count);
void(*CreateParticleEffect)(void *context, int type, vec3_t origin, unsigned int colorMin, unsigned int colorMax);
@ -49,6 +50,11 @@ void UQ_Game_SetEntitySkin(int entityNum, int skinNum)
unity_gamecalls->SetEntitySkin(unity_context, entityNum, skinNum);
}
void UQ_Game_SetEntityLighting(int entityNum, vec3_t shadeVector, vec3_t lightColor)
{
unity_gamecalls->SetEntityLighting(unity_context, entityNum, shadeVector, lightColor);
}
void UQ_Game_RunParticleEffect(vec3_t origin, vec3_t direction, int color, int count)
{
unsigned int colorMin, colorMax;

Loading…
Cancel
Save