mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2026-05-15 03:14:47 +08:00
Deferred shading
This commit is contained in:
+132
-22
@@ -1355,6 +1355,136 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class RenderableLODLights : RenderableCacheItem<YmapFile>
|
||||
{
|
||||
public struct LODLight
|
||||
{
|
||||
public Vector3 Position;
|
||||
public uint Colour;
|
||||
public Vector3 Direction;
|
||||
public uint TimeAndStateFlags;
|
||||
public Vector4 TangentX;
|
||||
public Vector4 TangentY;
|
||||
public float Falloff;
|
||||
public float FalloffExponent;
|
||||
public float InnerAngle;//for cone
|
||||
public float OuterAngleOrCapExt;//outer angle for cone, cap extent for capsule
|
||||
}
|
||||
|
||||
public LODLight[] Points;
|
||||
public LODLight[] Spots;
|
||||
public LODLight[] Caps;
|
||||
|
||||
public GpuSBuffer<LODLight> PointsBuffer { get; set; }
|
||||
public GpuSBuffer<LODLight> SpotsBuffer { get; set; }
|
||||
public GpuSBuffer<LODLight> CapsBuffer { get; set; }
|
||||
|
||||
|
||||
public override void Init(YmapFile key)
|
||||
{
|
||||
Key = key;
|
||||
|
||||
var ll = key.LODLights;
|
||||
var dll = key.Parent?.DistantLODLights;
|
||||
|
||||
if (ll == null) return;
|
||||
if (dll == null) return;
|
||||
|
||||
var n = dll.positions?.Length ?? 0;
|
||||
n = Math.Min(n, dll.colours?.Length ?? 0);
|
||||
n = Math.Min(n, ll.direction?.Length ?? 0);
|
||||
n = Math.Min(n, ll.falloff?.Length ?? 0);
|
||||
n = Math.Min(n, ll.falloffExponent?.Length ?? 0);
|
||||
n = Math.Min(n, ll.timeAndStateFlags?.Length ?? 0);
|
||||
n = Math.Min(n, ll.hash?.Length ?? 0);
|
||||
n = Math.Min(n, ll.coneInnerAngle?.Length ?? 0);
|
||||
n = Math.Min(n, ll.coneOuterAngleOrCapExt?.Length ?? 0);
|
||||
n = Math.Min(n, ll.coronaIntensity?.Length ?? 0);
|
||||
|
||||
if (n <= 0)
|
||||
{ return; }
|
||||
|
||||
|
||||
var points = new List<LODLight>();
|
||||
var spots = new List<LODLight>();
|
||||
var caps = new List<LODLight>();
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var light = new LODLight();
|
||||
light.Position = dll.positions[i].ToVector3();
|
||||
light.Colour = dll.colours[i];
|
||||
light.Direction = ll.direction[i].ToVector3();
|
||||
light.TimeAndStateFlags = ll.timeAndStateFlags[i];
|
||||
light.TangentX = new Vector4(Vector3.Normalize(light.Direction.GetPerpVec()), 0.0f);
|
||||
light.TangentY = new Vector4(Vector3.Cross(light.Direction, light.TangentX.XYZ()), 0.0f);
|
||||
light.Falloff = ll.falloff[i];
|
||||
light.FalloffExponent = ll.falloffExponent[i];
|
||||
light.InnerAngle = ll.coneInnerAngle[i];
|
||||
light.OuterAngleOrCapExt = ll.coneOuterAngleOrCapExt[i];
|
||||
var type = (LightType)((light.TimeAndStateFlags >> 26) & 7);
|
||||
switch (type)
|
||||
{
|
||||
case LightType.Point:
|
||||
points.Add(light);
|
||||
break;
|
||||
case LightType.Spot:
|
||||
spots.Add(light);
|
||||
break;
|
||||
case LightType.Capsule:
|
||||
caps.Add(light);
|
||||
break;
|
||||
default: break;//just checking...
|
||||
}
|
||||
}
|
||||
|
||||
Points = points.ToArray();
|
||||
Spots = spots.ToArray();
|
||||
Caps = caps.ToArray();
|
||||
|
||||
}
|
||||
|
||||
public override void Load(Device device)
|
||||
{
|
||||
if ((Points != null) && (Points.Length > 0))
|
||||
{
|
||||
PointsBuffer = new GpuSBuffer<LODLight>(device, Points);
|
||||
}
|
||||
if ((Spots != null) && (Spots.Length > 0))
|
||||
{
|
||||
SpotsBuffer = new GpuSBuffer<LODLight>(device, Spots);
|
||||
}
|
||||
if ((Caps != null) && (Caps.Length > 0))
|
||||
{
|
||||
CapsBuffer = new GpuSBuffer<LODLight>(device, Caps);
|
||||
}
|
||||
|
||||
IsLoaded = true;
|
||||
}
|
||||
|
||||
public override void Unload()
|
||||
{
|
||||
IsLoaded = false;
|
||||
|
||||
if (PointsBuffer != null)
|
||||
{
|
||||
PointsBuffer.Dispose();
|
||||
PointsBuffer = null;
|
||||
}
|
||||
if (SpotsBuffer != null)
|
||||
{
|
||||
SpotsBuffer.Dispose();
|
||||
SpotsBuffer = null;
|
||||
}
|
||||
if (CapsBuffer != null)
|
||||
{
|
||||
CapsBuffer.Dispose();
|
||||
CapsBuffer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RenderableDistantLODLights : RenderableCacheItem<YmapDistantLODLights>
|
||||
{
|
||||
public struct DistLODLight
|
||||
@@ -1815,7 +1945,7 @@ namespace CodeWalker.Rendering
|
||||
p2 = bgeom.GetVertex(bcap.capsuleIndex2);
|
||||
a1 = p2 - p1;
|
||||
n1 = Vector3.Normalize(a1);
|
||||
p3 = Vector3.Normalize(GetPerpVec(n1));
|
||||
p3 = Vector3.Normalize(n1.GetPerpVec());
|
||||
//p4 = Vector3.Normalize(Vector3.Cross(n1, p3));
|
||||
Quaternion q1 = Quaternion.Invert(Quaternion.LookAtRH(Vector3.Zero, p3, n1));
|
||||
rcapsules[curcapsule].Point1 = p1;
|
||||
@@ -1848,7 +1978,7 @@ namespace CodeWalker.Rendering
|
||||
p2 = bgeom.GetVertex(pcyl.cylinderIndex2);
|
||||
a1 = p2 - p1;
|
||||
n1 = Vector3.Normalize(a1);
|
||||
p3 = Vector3.Normalize(GetPerpVec(n1));
|
||||
p3 = Vector3.Normalize(n1.GetPerpVec());
|
||||
//p4 = Vector3.Normalize(Vector3.Cross(n1, p3));
|
||||
Quaternion q2 = Quaternion.Invert(Quaternion.LookAtRH(Vector3.Zero, p3, n1));
|
||||
rcylinders[curcylinder].Point1 = p1;
|
||||
@@ -1898,26 +2028,6 @@ namespace CodeWalker.Rendering
|
||||
index++;
|
||||
}
|
||||
|
||||
private Vector3 GetPerpVec(Vector3 n)
|
||||
{
|
||||
//make a vector perpendicular to the given one
|
||||
float nx = Math.Abs(n.X);
|
||||
float ny = Math.Abs(n.Y);
|
||||
float nz = Math.Abs(n.Z);
|
||||
if ((nx < ny) && (nx < nz))
|
||||
{
|
||||
return Vector3.Cross(n, Vector3.Right);
|
||||
}
|
||||
else if (ny < nz)
|
||||
{
|
||||
return Vector3.Cross(n, Vector3.Up);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Vector3.Cross(n, Vector3.ForwardLH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Load(Device device)
|
||||
{
|
||||
|
||||
@@ -29,8 +29,9 @@ namespace CodeWalker.Rendering
|
||||
return renderables.CacheUse
|
||||
+ textures.CacheUse
|
||||
+ boundcomps.CacheUse
|
||||
+ instbatches.CacheUse
|
||||
+ distlodlights.CacheUse
|
||||
+ instbatches.CacheUse
|
||||
+ lodlights.CacheUse
|
||||
+ distlodlights.CacheUse
|
||||
+ pathbatches.CacheUse
|
||||
+ waterquads.CacheUse;
|
||||
}
|
||||
@@ -43,6 +44,7 @@ namespace CodeWalker.Rendering
|
||||
+ textures.CurrentLoadedCount
|
||||
+ boundcomps.CurrentLoadedCount
|
||||
+ instbatches.CurrentLoadedCount
|
||||
+ lodlights.CurrentLoadedCount
|
||||
+ distlodlights.CurrentLoadedCount
|
||||
+ pathbatches.CurrentLoadedCount
|
||||
+ waterquads.CurrentLoadedCount;
|
||||
@@ -56,6 +58,7 @@ namespace CodeWalker.Rendering
|
||||
+ textures.QueueLength
|
||||
+ boundcomps.QueueLength
|
||||
+ instbatches.QueueLength
|
||||
+ lodlights.QueueLength
|
||||
+ distlodlights.QueueLength
|
||||
+ pathbatches.QueueLength
|
||||
+ waterquads.QueueLength;
|
||||
@@ -95,6 +98,7 @@ namespace CodeWalker.Rendering
|
||||
private RenderableCacheLookup<Texture, RenderableTexture> textures = new RenderableCacheLookup<Texture, RenderableTexture>(Settings.Default.GPUTextureCacheSize, Settings.Default.GPUCacheTime);
|
||||
private RenderableCacheLookup<BoundComposite, RenderableBoundComposite> boundcomps = new RenderableCacheLookup<BoundComposite, RenderableBoundComposite>(Settings.Default.GPUBoundCompCacheSize, Settings.Default.GPUCacheTime);
|
||||
private RenderableCacheLookup<YmapGrassInstanceBatch, RenderableInstanceBatch> instbatches = new RenderableCacheLookup<YmapGrassInstanceBatch, RenderableInstanceBatch>(67108864, Settings.Default.GPUCacheTime); //64MB - todo: make this a setting
|
||||
private RenderableCacheLookup<YmapFile, RenderableLODLights> lodlights = new RenderableCacheLookup<YmapFile, RenderableLODLights>(33554432, Settings.Default.GPUCacheTime); //32MB - todo: make this a setting
|
||||
private RenderableCacheLookup<YmapDistantLODLights, RenderableDistantLODLights> distlodlights = new RenderableCacheLookup<YmapDistantLODLights, RenderableDistantLODLights>(33554432, Settings.Default.GPUCacheTime); //32MB - todo: make this a setting
|
||||
private RenderableCacheLookup<BasePathData, RenderablePathBatch> pathbatches = new RenderableCacheLookup<BasePathData, RenderablePathBatch>(536870912 /*33554432*/, Settings.Default.GPUCacheTime); // 512MB /*32MB*/ - todo: make this a setting
|
||||
private RenderableCacheLookup<WaterQuad, RenderableWaterQuad> waterquads = new RenderableCacheLookup<WaterQuad, RenderableWaterQuad>(4194304, Settings.Default.GPUCacheTime); //4MB - todo: make this a setting
|
||||
@@ -117,6 +121,7 @@ namespace CodeWalker.Rendering
|
||||
textures.Clear();
|
||||
boundcomps.Clear();
|
||||
instbatches.Clear();
|
||||
lodlights.Clear();
|
||||
distlodlights.Clear();
|
||||
pathbatches.Clear();
|
||||
waterquads.Clear();
|
||||
@@ -134,6 +139,7 @@ namespace CodeWalker.Rendering
|
||||
int texturecount = textures.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||
int boundcompcount = boundcomps.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||
int instbatchcount = instbatches.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||
int lodlightcount = lodlights.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||
int distlodlightcount = distlodlights.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||
int pathbatchcount = pathbatches.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||
int waterquadcount = waterquads.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||
@@ -144,6 +150,7 @@ namespace CodeWalker.Rendering
|
||||
(texturecount >= MaxItemsPerLoop) ||
|
||||
(boundcompcount >= MaxItemsPerLoop) ||
|
||||
(instbatchcount >= MaxItemsPerLoop) ||
|
||||
(lodlightcount >= MaxItemsPerLoop) ||
|
||||
(distlodlightcount >= MaxItemsPerLoop) ||
|
||||
(pathbatchcount >= MaxItemsPerLoop) ||
|
||||
(waterquadcount >= MaxItemsPerLoop);
|
||||
@@ -161,6 +168,7 @@ namespace CodeWalker.Rendering
|
||||
textures.UnloadProc();
|
||||
boundcomps.UnloadProc();
|
||||
instbatches.UnloadProc();
|
||||
lodlights.UnloadProc();
|
||||
distlodlights.UnloadProc();
|
||||
pathbatches.UnloadProc();
|
||||
waterquads.UnloadProc();
|
||||
@@ -182,6 +190,7 @@ namespace CodeWalker.Rendering
|
||||
textures.RenderThreadSync();
|
||||
boundcomps.RenderThreadSync();
|
||||
instbatches.RenderThreadSync();
|
||||
lodlights.RenderThreadSync();
|
||||
distlodlights.RenderThreadSync();
|
||||
pathbatches.RenderThreadSync();
|
||||
waterquads.RenderThreadSync();
|
||||
@@ -207,6 +216,10 @@ namespace CodeWalker.Rendering
|
||||
{
|
||||
return distlodlights.Get(lights);
|
||||
}
|
||||
public RenderableLODLights GetRenderableLODLights(YmapFile ymap)
|
||||
{
|
||||
return lodlights.Get(ymap);
|
||||
}
|
||||
public RenderablePathBatch GetRenderablePathBatch(BasePathData pathdata)
|
||||
{
|
||||
return pathbatches.Get(pathdata);
|
||||
|
||||
+35
-4
@@ -102,7 +102,9 @@ namespace CodeWalker.Rendering
|
||||
public bool renderchildents = false;//when rendering single ymap, render root only or not...
|
||||
public bool renderentities = true;
|
||||
public bool rendergrass = true;
|
||||
public bool renderdistlodlights = true;
|
||||
public bool renderlights = false; //render individual drawable lights (TODO!)
|
||||
public bool renderlodlights = true; //render LOD lights from ymaps
|
||||
public bool renderdistlodlights = true; //render distant lod lights (coronas)
|
||||
public bool rendercars = false;
|
||||
|
||||
public bool rendercollisionmeshes = Settings.Default.ShowCollisionMeshes;
|
||||
@@ -1575,10 +1577,14 @@ namespace CodeWalker.Rendering
|
||||
for (int y = 0; y < VisibleYmaps.Count; y++)
|
||||
{
|
||||
var ymap = VisibleYmaps[y];
|
||||
YmapFile pymap = ymap.Parent;
|
||||
if ((pymap == null) && (ymap._CMapData.parent != 0))
|
||||
{
|
||||
renderworldVisibleYmapDict.TryGetValue(ymap._CMapData.parent, out pymap);
|
||||
ymap.Parent = pymap;
|
||||
}
|
||||
if (ymap.RootEntities != null)
|
||||
{
|
||||
YmapFile pymap;
|
||||
renderworldVisibleYmapDict.TryGetValue(ymap._CMapData.parent, out pymap);
|
||||
for (int i = 0; i < ymap.RootEntities.Length; i++)
|
||||
{
|
||||
var ent = ymap.RootEntities[i];
|
||||
@@ -1699,6 +1705,17 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
}
|
||||
}
|
||||
if (renderlodlights && shaders.deferred)
|
||||
{
|
||||
for (int y = 0; y < VisibleYmaps.Count; y++)
|
||||
{
|
||||
var ymap = VisibleYmaps[y];
|
||||
if (ymap.LODLights != null)
|
||||
{
|
||||
RenderYmapLODLights(ymap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool RenderWorldYmapIsVisible(YmapFile ymap)
|
||||
{
|
||||
@@ -2185,6 +2202,20 @@ namespace CodeWalker.Rendering
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void RenderYmapLODLights(YmapFile ymap)
|
||||
{
|
||||
if (ymap.LODLights == null) return;
|
||||
if (ymap.Parent?.DistantLODLights == null) return; //need to get lodlights positions from parent (distlodlights)
|
||||
|
||||
RenderableLODLights lights = renderableCache.GetRenderableLODLights(ymap);
|
||||
if (!lights.IsLoaded) return;
|
||||
|
||||
shaders.Enqueue(lights);
|
||||
|
||||
}
|
||||
|
||||
private void RenderYmapDistantLODLights(YmapFile ymap)
|
||||
{
|
||||
//enqueue ymap DistantLODLights instance batch for rendering
|
||||
@@ -2211,7 +2242,7 @@ namespace CodeWalker.Rendering
|
||||
Texture lighttex = null;
|
||||
if ((graphicsytd != null) && (graphicsytd.Loaded) && (graphicsytd.TextureDict != null) && (graphicsytd.TextureDict.Dict != null))
|
||||
{
|
||||
graphicsytd.TextureDict.Dict.TryGetValue(texhash, out lighttex); //starfield hash
|
||||
graphicsytd.TextureDict.Dict.TryGetValue(texhash, out lighttex);
|
||||
}
|
||||
|
||||
if (lighttex == null) return;
|
||||
|
||||
+110
-18
@@ -32,9 +32,11 @@ namespace CodeWalker.Rendering
|
||||
DepthStencilState dsDisableAll;
|
||||
DepthStencilState dsDisableComp;
|
||||
DepthStencilState dsDisableWrite;
|
||||
DepthStencilState dsDisableWriteRev;
|
||||
|
||||
|
||||
|
||||
public DeferredScene DefScene { get; set; }
|
||||
public PostProcessor HDR { get; set; }
|
||||
public BasicShader Basic { get; set; }
|
||||
public CableShader Cable { get; set; }
|
||||
@@ -57,6 +59,7 @@ namespace CodeWalker.Rendering
|
||||
List<ShaderBatch> shadowbatches = new List<ShaderBatch>();
|
||||
int shadowcastercount = 0; //total casters rendered
|
||||
|
||||
public bool deferred = Settings.Default.Deferred;
|
||||
public bool hdr = Settings.Default.HDR;
|
||||
public float hdrLumBlendSpeed = 1.0f;
|
||||
int Width;
|
||||
@@ -68,6 +71,7 @@ namespace CodeWalker.Rendering
|
||||
public List<ShaderRenderBucket> RenderBuckets = new List<ShaderRenderBucket>();
|
||||
public List<RenderableBoundGeometryInst> RenderBoundGeoms = new List<RenderableBoundGeometryInst>();
|
||||
public List<RenderableInstanceBatchInst> RenderInstBatches = new List<RenderableInstanceBatchInst>();
|
||||
public List<RenderableLODLights> RenderLODLights = new List<RenderableLODLights>();
|
||||
public List<RenderableDistantLODLights> RenderDistLODLights = new List<RenderableDistantLODLights>();
|
||||
public List<RenderablePathBatch> RenderPathBatches = new List<RenderablePathBatch>();
|
||||
public List<RenderableWaterQuad> RenderWaterQuads = new List<RenderableWaterQuad>();
|
||||
@@ -94,6 +98,10 @@ namespace CodeWalker.Rendering
|
||||
get
|
||||
{
|
||||
long u = 0;
|
||||
if (DefScene != null)
|
||||
{
|
||||
u += DefScene.VramUsage;
|
||||
}
|
||||
if (HDR != null)
|
||||
{
|
||||
u += HDR.VramUsage;
|
||||
@@ -163,6 +171,9 @@ namespace CodeWalker.Rendering
|
||||
bsd.RenderTarget[0].RenderTargetWriteMask = ColorWriteMaskFlags.All;
|
||||
bsd.RenderTarget[0].SourceAlphaBlend = BlendOption.Zero;
|
||||
bsd.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha;
|
||||
bsd.RenderTarget[1] = bsd.RenderTarget[0];
|
||||
bsd.RenderTarget[2] = bsd.RenderTarget[0];
|
||||
bsd.RenderTarget[3] = bsd.RenderTarget[0];
|
||||
bsDefault = new BlendState(device, bsd);
|
||||
|
||||
bsd.AlphaToCoverageEnable = true;
|
||||
@@ -198,6 +209,8 @@ namespace CodeWalker.Rendering
|
||||
dsEnabled = new DepthStencilState(device, dsd);
|
||||
dsd.DepthWriteMask = DepthWriteMask.Zero;
|
||||
dsDisableWrite = new DepthStencilState(device, dsd);
|
||||
dsd.DepthComparison = Comparison.LessEqual;
|
||||
dsDisableWriteRev = new DepthStencilState(device, dsd);
|
||||
dsd.DepthComparison = Comparison.Always;
|
||||
dsDisableComp = new DepthStencilState(device, dsd);
|
||||
dsd.IsDepthEnabled = false;
|
||||
@@ -212,6 +225,7 @@ namespace CodeWalker.Rendering
|
||||
disposed = true;
|
||||
|
||||
dsEnabled.Dispose();
|
||||
dsDisableWriteRev.Dispose();
|
||||
dsDisableWrite.Dispose();
|
||||
dsDisableComp.Dispose();
|
||||
dsDisableAll.Dispose();
|
||||
@@ -235,6 +249,13 @@ namespace CodeWalker.Rendering
|
||||
Cable.Dispose();
|
||||
Water.Dispose();
|
||||
|
||||
|
||||
if (DefScene != null)
|
||||
{
|
||||
DefScene.Dispose();
|
||||
DefScene = null;
|
||||
}
|
||||
|
||||
if (HDR != null)
|
||||
{
|
||||
HDR.Dispose();
|
||||
@@ -286,6 +307,16 @@ namespace CodeWalker.Rendering
|
||||
HDR.Dispose();
|
||||
HDR = null;
|
||||
}
|
||||
if (deferred && (DefScene == null))
|
||||
{
|
||||
DefScene = new DeferredScene(DXMan);
|
||||
DefScene.OnWindowResize(DXMan);
|
||||
}
|
||||
if (!deferred && (DefScene != null))
|
||||
{
|
||||
DefScene.Dispose();
|
||||
DefScene = null;
|
||||
}
|
||||
|
||||
|
||||
foreach (var bucket in RenderBuckets)
|
||||
@@ -295,10 +326,16 @@ namespace CodeWalker.Rendering
|
||||
|
||||
RenderBoundGeoms.Clear();
|
||||
RenderInstBatches.Clear();
|
||||
RenderLODLights.Clear();
|
||||
RenderDistLODLights.Clear();
|
||||
RenderPathBatches.Clear();
|
||||
RenderWaterQuads.Clear();
|
||||
|
||||
|
||||
if (DefScene != null)
|
||||
{
|
||||
DefScene.Clear(context);
|
||||
}
|
||||
if (HDR != null)
|
||||
{
|
||||
HDR.Clear(context);
|
||||
@@ -312,6 +349,12 @@ namespace CodeWalker.Rendering
|
||||
|
||||
Skydome.EnableHDR = hdr;
|
||||
Clouds.EnableHDR = hdr;
|
||||
|
||||
Basic.Deferred = deferred;
|
||||
Cable.Deferred = deferred;
|
||||
Water.Deferred = deferred;
|
||||
Terrain.Deferred = deferred;
|
||||
TreesLod.Deferred = deferred;
|
||||
}
|
||||
|
||||
|
||||
@@ -384,7 +427,11 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
|
||||
|
||||
if (HDR != null)
|
||||
if (DefScene != null)
|
||||
{
|
||||
DefScene.SetPrimary(context);
|
||||
}
|
||||
else if (HDR != null)
|
||||
{
|
||||
HDR.SetPrimary(context);
|
||||
}
|
||||
@@ -459,22 +506,6 @@ namespace CodeWalker.Rendering
|
||||
context.OutputMerger.BlendState = bsDefault;
|
||||
}
|
||||
|
||||
if (RenderDistLODLights.Count > 0) //LOD lights pass
|
||||
{
|
||||
context.Rasterizer.State = rsSolidDblSided;
|
||||
context.OutputMerger.BlendState = bsAdd; //additive blend for distant lod lights...
|
||||
context.OutputMerger.DepthStencilState = dsDisableWrite;
|
||||
DistLights.SetShader(context);
|
||||
DistLights.SetSceneVars(context, Camera, Shadowmap, GlobalLights);
|
||||
for (int i = 0; i < RenderDistLODLights.Count; i++)
|
||||
{
|
||||
DistLights.RenderBatch(context, RenderDistLODLights[i]);
|
||||
}
|
||||
DistLights.UnbindResources(context);
|
||||
context.OutputMerger.BlendState = bsDefault;
|
||||
context.OutputMerger.DepthStencilState = dsEnabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -505,6 +536,9 @@ namespace CodeWalker.Rendering
|
||||
Water.UnbindResources(context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//TODO: needs second gbuffer pass?
|
||||
Basic.DecalMode = true;
|
||||
for (int i = 0; i < RenderBuckets.Count; i++) //alphablended and glass pass
|
||||
{
|
||||
@@ -525,6 +559,54 @@ namespace CodeWalker.Rendering
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (DefScene != null)
|
||||
{
|
||||
if (HDR != null)
|
||||
{
|
||||
HDR.SetPrimary(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
DXMan.SetDefaultRenderTarget(context);
|
||||
}
|
||||
|
||||
DefScene.RenderLights(context, camera, Shadowmap, GlobalLights);
|
||||
|
||||
if (RenderLODLights.Count > 0) //LOD lights pass
|
||||
{
|
||||
context.Rasterizer.State = rsSolid;
|
||||
context.OutputMerger.BlendState = bsAdd; //additive blend for lights...
|
||||
context.OutputMerger.DepthStencilState = dsDisableWriteRev;//only render parts behind or at surface
|
||||
DefScene.RenderLights(context, camera, RenderLODLights);
|
||||
}
|
||||
}
|
||||
|
||||
Basic.Deferred = false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (RenderDistLODLights.Count > 0) //distant LOD lights pass
|
||||
{
|
||||
context.Rasterizer.State = rsSolidDblSided;
|
||||
context.OutputMerger.BlendState = bsAdd; //additive blend for distant lod lights...
|
||||
context.OutputMerger.DepthStencilState = dsDisableWrite;
|
||||
DistLights.SetShader(context);
|
||||
DistLights.SetSceneVars(context, Camera, Shadowmap, GlobalLights);
|
||||
for (int i = 0; i < RenderDistLODLights.Count; i++)
|
||||
{
|
||||
DistLights.RenderBatch(context, RenderDistLODLights[i]);
|
||||
}
|
||||
DistLights.UnbindResources(context);
|
||||
context.OutputMerger.BlendState = bsDefault;
|
||||
context.OutputMerger.DepthStencilState = dsEnabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (RenderBoundGeoms.Count > 0) //collision meshes pass
|
||||
{
|
||||
ClearDepth(context); //draw over everything else
|
||||
@@ -550,6 +632,8 @@ namespace CodeWalker.Rendering
|
||||
|
||||
|
||||
|
||||
Basic.Deferred = deferred;
|
||||
|
||||
RenderedGeometries = GeometryCount;
|
||||
|
||||
}
|
||||
@@ -696,7 +780,7 @@ namespace CodeWalker.Rendering
|
||||
{
|
||||
Basic.RenderMode = WorldRenderMode.VertexColour;
|
||||
Basic.SetShader(context);
|
||||
Basic.SetSceneVars(context, Camera, Shadowmap, GlobalLights);
|
||||
Basic.SetSceneVars(context, Camera, /*Shadowmap*/ null, GlobalLights);//should this be using shadows??
|
||||
Basic.SetInputLayout(context, VertexType.Default);
|
||||
|
||||
GeometryCount += batch.Count;
|
||||
@@ -764,6 +848,10 @@ namespace CodeWalker.Rendering
|
||||
{
|
||||
RenderInstBatches.Add(batch);
|
||||
}
|
||||
public void Enqueue(RenderableLODLights lights)
|
||||
{
|
||||
RenderLODLights.Add(lights);
|
||||
}
|
||||
public void Enqueue(RenderableDistantLODLights lights)
|
||||
{
|
||||
RenderDistLODLights.Add(lights);
|
||||
@@ -880,6 +968,10 @@ namespace CodeWalker.Rendering
|
||||
{
|
||||
Width = w;
|
||||
Height = h;
|
||||
if (DefScene != null)
|
||||
{
|
||||
DefScene.OnWindowResize(DXMan);
|
||||
}
|
||||
if (HDR != null)
|
||||
{
|
||||
HDR.OnWindowResize(DXMan);
|
||||
|
||||
@@ -145,6 +145,7 @@ namespace CodeWalker.Rendering
|
||||
VertexShader basicvscapsule;
|
||||
VertexShader basicvscylinder;
|
||||
PixelShader basicps;
|
||||
PixelShader basicpsdef;
|
||||
GpuVarsBuffer<BasicShaderVSSceneVars> VSSceneVars;
|
||||
GpuVarsBuffer<BasicShaderVSEntityVars> VSEntityVars;
|
||||
GpuVarsBuffer<BasicShaderVSModelVars> VSModelVars;
|
||||
@@ -174,6 +175,7 @@ namespace CodeWalker.Rendering
|
||||
public int RenderTextureSamplerCoord = 1;
|
||||
public ShaderParamNames RenderTextureSampler = ShaderParamNames.DiffuseSampler;
|
||||
public bool SpecularEnable = true;
|
||||
public bool Deferred = false;
|
||||
|
||||
Matrix3_s[] defaultBoneMatrices;
|
||||
bool defaultBoneMatricesBound = false;
|
||||
@@ -209,6 +211,7 @@ namespace CodeWalker.Rendering
|
||||
byte[] vscapsulebytes = File.ReadAllBytes("Shaders\\BasicVS_Capsule.cso");
|
||||
byte[] vscylinderbytes = File.ReadAllBytes("Shaders\\BasicVS_Cylinder.cso");
|
||||
byte[] psbytes = File.ReadAllBytes("Shaders\\BasicPS.cso");
|
||||
byte[] psdefbytes = File.ReadAllBytes("Shaders\\BasicPS_Deferred.cso");
|
||||
|
||||
basicvspnct = new VertexShader(device, vspnctbytes);
|
||||
basicvspnctt = new VertexShader(device, vspncttbytes);
|
||||
@@ -235,6 +238,7 @@ namespace CodeWalker.Rendering
|
||||
basicvscapsule = new VertexShader(device, vscapsulebytes);
|
||||
basicvscylinder = new VertexShader(device, vscylinderbytes);
|
||||
basicps = new PixelShader(device, psbytes);
|
||||
basicpsdef = new PixelShader(device, psdefbytes);
|
||||
|
||||
VSSceneVars = new GpuVarsBuffer<BasicShaderVSSceneVars>(device);
|
||||
VSEntityVars = new GpuVarsBuffer<BasicShaderVSEntityVars>(device);
|
||||
@@ -491,7 +495,7 @@ namespace CodeWalker.Rendering
|
||||
|
||||
public override void SetShader(DeviceContext context)
|
||||
{
|
||||
context.PixelShader.Set(basicps);
|
||||
context.PixelShader.Set(Deferred ? basicpsdef : basicps);
|
||||
}
|
||||
|
||||
public override bool SetInputLayout(DeviceContext context, VertexType type)
|
||||
@@ -1035,6 +1039,7 @@ namespace CodeWalker.Rendering
|
||||
ClothVertices.Dispose();
|
||||
|
||||
basicps.Dispose();
|
||||
basicpsdef.Dispose();
|
||||
basicvspnct.Dispose();
|
||||
basicvspnctt.Dispose();
|
||||
basicvspncttt.Dispose();
|
||||
|
||||
@@ -67,6 +67,7 @@ namespace CodeWalker.Rendering
|
||||
|
||||
VertexShader vs;
|
||||
PixelShader ps;
|
||||
PixelShader psdef;
|
||||
GpuVarsBuffer<CableShaderVSSceneVars> VSSceneVars;
|
||||
GpuVarsBuffer<CableShaderVSEntityVars> VSEntityVars;
|
||||
GpuVarsBuffer<CableShaderVSModelVars> VSModelVars;
|
||||
@@ -80,6 +81,7 @@ namespace CodeWalker.Rendering
|
||||
public int RenderTextureCoordIndex = 1;
|
||||
public int RenderTextureSamplerCoord = 1;
|
||||
public ShaderParamNames RenderTextureSampler = ShaderParamNames.DiffuseSampler;
|
||||
public bool Deferred = false;
|
||||
|
||||
|
||||
private Dictionary<VertexType, InputLayout> layouts = new Dictionary<VertexType, InputLayout>();
|
||||
@@ -88,9 +90,11 @@ namespace CodeWalker.Rendering
|
||||
{
|
||||
byte[] vsbytes = File.ReadAllBytes("Shaders\\CableVS.cso");
|
||||
byte[] psbytes = File.ReadAllBytes("Shaders\\CablePS.cso");
|
||||
byte[] psdefbytes = File.ReadAllBytes("Shaders\\CablePS_Deferred.cso");
|
||||
|
||||
vs = new VertexShader(device, vsbytes);
|
||||
ps = new PixelShader(device, psbytes);
|
||||
psdef = new PixelShader(device, psdefbytes);
|
||||
|
||||
|
||||
VSSceneVars = new GpuVarsBuffer<CableShaderVSSceneVars>(device);
|
||||
@@ -137,7 +141,7 @@ namespace CodeWalker.Rendering
|
||||
|
||||
public override void SetShader(DeviceContext context)
|
||||
{
|
||||
context.PixelShader.Set(ps);
|
||||
context.PixelShader.Set(Deferred ? psdef : ps);
|
||||
}
|
||||
|
||||
public override bool SetInputLayout(DeviceContext context, VertexType type)
|
||||
@@ -344,6 +348,7 @@ namespace CodeWalker.Rendering
|
||||
|
||||
|
||||
ps.Dispose();
|
||||
psdef.Dispose();
|
||||
vs.Dispose();
|
||||
|
||||
disposed = true;
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Device = SharpDX.Direct3D11.Device;
|
||||
using Buffer = SharpDX.Direct3D11.Buffer;
|
||||
using MapFlags = SharpDX.Direct3D11.MapFlags;
|
||||
using SharpDX.Direct3D11;
|
||||
using System.IO;
|
||||
using CodeWalker.GameFiles;
|
||||
using CodeWalker.World;
|
||||
using SharpDX;
|
||||
using SharpDX.DXGI;
|
||||
using SharpDX.Mathematics.Interop;
|
||||
|
||||
namespace CodeWalker.Rendering
|
||||
{
|
||||
|
||||
public struct DeferredLightVSVars
|
||||
{
|
||||
public Matrix ViewProj;
|
||||
public Vector4 CameraPos;
|
||||
public uint LightType; //0=directional, 1=Point, 2=Spot, 4=Capsule
|
||||
public uint IsLOD; //useful or not?
|
||||
public uint Pad0;
|
||||
public uint Pad1;
|
||||
}
|
||||
public struct DeferredLightPSVars
|
||||
{
|
||||
public ShaderGlobalLightParams GlobalLights;
|
||||
public Matrix ViewProjInv;
|
||||
public Vector4 CameraPos;
|
||||
public uint EnableShadows;
|
||||
public uint RenderMode;//0=default, 1=normals, 2=tangents, 3=colours, 4=texcoords, 5=diffuse, 6=normalmap, 7=spec, 8=direct
|
||||
public uint RenderModeIndex; //colour/texcoord index
|
||||
public uint RenderSamplerCoord; //which texcoord to use in single texture mode
|
||||
public uint LightType; //0=directional, 1=Point, 2=Spot, 4=Capsule
|
||||
public uint IsLOD; //useful or not?
|
||||
public uint Pad0;
|
||||
public uint Pad1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class DeferredScene
|
||||
{
|
||||
|
||||
public GpuMultiTexture GBuffers; // diffuse, normals, specular, irradiance
|
||||
|
||||
SamplerState SampleStatePoint;
|
||||
SamplerState SampleStateLinear;
|
||||
BlendState BlendState;
|
||||
long WindowSizeVramUsage = 0;
|
||||
int Width = 0;
|
||||
int Height = 0;
|
||||
ViewportF Viewport;
|
||||
|
||||
VertexShader LightVS;
|
||||
PixelShader LightPS;
|
||||
UnitCone LightCone;
|
||||
UnitSphere LightSphere;
|
||||
UnitCapsule LightCapsule;
|
||||
UnitQuad LightQuad;
|
||||
InputLayout LightQuadLayout;
|
||||
|
||||
|
||||
GpuVarsBuffer<DeferredLightVSVars> LightVSVars;
|
||||
GpuVarsBuffer<DeferredLightPSVars> LightPSVars;
|
||||
|
||||
|
||||
|
||||
public long VramUsage
|
||||
{
|
||||
get
|
||||
{
|
||||
return WindowSizeVramUsage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public DeferredScene(DXManager dxman)
|
||||
{
|
||||
var device = dxman.device;
|
||||
|
||||
byte[] bLightVS = File.ReadAllBytes("Shaders\\LightVS.cso");
|
||||
byte[] bLightPS = File.ReadAllBytes("Shaders\\LightPS.cso");
|
||||
|
||||
LightVS = new VertexShader(device, bLightVS);
|
||||
LightPS = new PixelShader(device, bLightPS);
|
||||
LightCone = new UnitCone(device, bLightVS, 4, false);
|
||||
LightSphere = new UnitSphere(device, bLightVS, 4, true);
|
||||
LightCapsule = new UnitCapsule(device, bLightVS, 4, false);
|
||||
LightQuad = new UnitQuad(device, true);
|
||||
LightQuadLayout = new InputLayout(device, bLightVS, new[]
|
||||
{
|
||||
new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
|
||||
new InputElement("TEXCOORD", 0, Format.R32G32_Float, 16, 0),
|
||||
});
|
||||
|
||||
LightVSVars = new GpuVarsBuffer<DeferredLightVSVars>(device);
|
||||
LightPSVars = new GpuVarsBuffer<DeferredLightPSVars>(device);
|
||||
|
||||
TextureAddressMode a = TextureAddressMode.Clamp;
|
||||
Color4 b = new Color4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
Comparison c = Comparison.Always;
|
||||
SampleStatePoint = DXUtility.CreateSamplerState(device, a, b, c, Filter.MinMagMipPoint, 0, 1.0f, 1.0f, 0.0f);
|
||||
SampleStateLinear = DXUtility.CreateSamplerState(device, a, b, c, Filter.MinMagMipLinear, 0, 1.0f, 1.0f, 0.0f);
|
||||
|
||||
BlendState = DXUtility.CreateBlendState(device, false, BlendOperation.Add, BlendOption.One, BlendOption.Zero, BlendOperation.Add, BlendOption.One, BlendOption.Zero, ColorWriteMaskFlags.All);
|
||||
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeBuffers();
|
||||
|
||||
if (BlendState != null)
|
||||
{
|
||||
BlendState.Dispose();
|
||||
BlendState = null;
|
||||
}
|
||||
if (SampleStateLinear != null)
|
||||
{
|
||||
SampleStateLinear.Dispose();
|
||||
SampleStateLinear = null;
|
||||
}
|
||||
if (SampleStatePoint != null)
|
||||
{
|
||||
SampleStatePoint.Dispose();
|
||||
SampleStatePoint = null;
|
||||
}
|
||||
if (LightVSVars != null)
|
||||
{
|
||||
LightVSVars.Dispose();
|
||||
LightVSVars = null;
|
||||
}
|
||||
if (LightPSVars != null)
|
||||
{
|
||||
LightPSVars.Dispose();
|
||||
LightPSVars = null;
|
||||
}
|
||||
if (LightQuadLayout != null)
|
||||
{
|
||||
LightQuadLayout.Dispose();
|
||||
LightQuadLayout = null;
|
||||
}
|
||||
if (LightQuad != null)
|
||||
{
|
||||
LightQuad.Dispose();
|
||||
LightQuad = null;
|
||||
}
|
||||
if (LightCone != null)
|
||||
{
|
||||
LightCone.Dispose();
|
||||
LightCone = null;
|
||||
}
|
||||
if (LightSphere != null)
|
||||
{
|
||||
LightSphere.Dispose();
|
||||
LightSphere = null;
|
||||
}
|
||||
if (LightCapsule != null)
|
||||
{
|
||||
LightCapsule.Dispose();
|
||||
LightCapsule = null;
|
||||
}
|
||||
if (LightPS != null)
|
||||
{
|
||||
LightPS.Dispose();
|
||||
LightPS = null;
|
||||
}
|
||||
if (LightVS != null)
|
||||
{
|
||||
LightVS.Dispose();
|
||||
LightVS = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnWindowResize(DXManager dxman)
|
||||
{
|
||||
DisposeBuffers();
|
||||
|
||||
var device = dxman.device;
|
||||
|
||||
|
||||
|
||||
int uw = Width = dxman.backbuffer.Description.Width;
|
||||
int uh = Height = dxman.backbuffer.Description.Height;
|
||||
Viewport = new ViewportF();
|
||||
Viewport.Width = (float)uw;
|
||||
Viewport.Height = (float)uh;
|
||||
Viewport.MinDepth = 0.0f;
|
||||
Viewport.MaxDepth = 1.0f;
|
||||
Viewport.X = 0.0f;
|
||||
Viewport.Y = 0.0f;
|
||||
|
||||
|
||||
GBuffers = new GpuMultiTexture(device, uw, uh, 4, Format.R8G8B8A8_UNorm, true, Format.D32_Float);
|
||||
WindowSizeVramUsage += GBuffers.VramUsage;
|
||||
|
||||
}
|
||||
public void DisposeBuffers()
|
||||
{
|
||||
if (GBuffers != null)
|
||||
{
|
||||
GBuffers.Dispose();
|
||||
GBuffers = null;
|
||||
}
|
||||
WindowSizeVramUsage = 0;
|
||||
}
|
||||
|
||||
public void Clear(DeviceContext context)
|
||||
{
|
||||
//Color4 clearColour = new Color4(0.2f, 0.4f, 0.6f, 0.0f);
|
||||
Color4 clearColour = new Color4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
GBuffers.Clear(context, clearColour);
|
||||
}
|
||||
public void ClearDepth(DeviceContext context)
|
||||
{
|
||||
GBuffers.ClearDepth(context);
|
||||
}
|
||||
public void SetPrimary(DeviceContext context)
|
||||
{
|
||||
GBuffers.SetRenderTargets(context);
|
||||
context.Rasterizer.SetViewport(Viewport);
|
||||
}
|
||||
|
||||
public void RenderLights(DeviceContext context, Camera camera, Shadowmap globalShadows, ShaderGlobalLights globalLights)
|
||||
{
|
||||
uint rendermode = 0;
|
||||
uint rendermodeind = 1;
|
||||
|
||||
//first full-screen directional light pass, for sun/moon
|
||||
//discard pixels where scene depth is 0, since nothing was rendered there
|
||||
//blend mode: overwrite
|
||||
|
||||
context.VertexShader.Set(LightVS);
|
||||
context.PixelShader.Set(LightPS);
|
||||
|
||||
LightVSVars.Vars.ViewProj = Matrix.Identity; //Matrix.Transpose(camera.ViewProjMatrix);
|
||||
LightVSVars.Vars.CameraPos = Vector4.Zero; //new Vector4(camera.Position, 0.0f);
|
||||
LightVSVars.Vars.LightType = 0;
|
||||
LightVSVars.Vars.IsLOD = 0;
|
||||
LightVSVars.Vars.Pad0 = 0;
|
||||
LightVSVars.Vars.Pad1 = 0;
|
||||
LightVSVars.Update(context);
|
||||
LightVSVars.SetVSCBuffer(context, 0);
|
||||
|
||||
LightPSVars.Vars.GlobalLights = globalLights.Params;
|
||||
LightPSVars.Vars.ViewProjInv = Matrix.Transpose(camera.ViewProjInvMatrix);
|
||||
LightPSVars.Vars.CameraPos = Vector4.Zero; //new Vector4(camera.Position, 0.0f);
|
||||
LightPSVars.Vars.EnableShadows = (globalShadows != null) ? 1u : 0u;
|
||||
LightPSVars.Vars.RenderMode = rendermode;
|
||||
LightPSVars.Vars.RenderModeIndex = rendermodeind;
|
||||
LightPSVars.Vars.RenderSamplerCoord = 0;// (uint)RenderTextureSamplerCoord;
|
||||
LightPSVars.Vars.LightType = 0;
|
||||
LightPSVars.Vars.IsLOD = 0;
|
||||
LightPSVars.Vars.Pad0 = 0;
|
||||
LightPSVars.Vars.Pad1 = 0;
|
||||
LightPSVars.Update(context);
|
||||
LightPSVars.SetPSCBuffer(context, 0);
|
||||
|
||||
context.PixelShader.SetShaderResources(0, GBuffers.DepthSRV);
|
||||
context.PixelShader.SetShaderResources(2, GBuffers.SRVs);
|
||||
|
||||
if (globalShadows != null)
|
||||
{
|
||||
globalShadows.SetFinalRenderResources(context);
|
||||
}
|
||||
|
||||
context.InputAssembler.InputLayout = LightQuadLayout;
|
||||
LightQuad.Draw(context);
|
||||
|
||||
|
||||
context.VertexShader.Set(null);
|
||||
context.PixelShader.Set(null);
|
||||
context.PixelShader.SetShaderResources(0, null, null, null);
|
||||
context.PixelShader.SetSamplers(0, null, null);
|
||||
}
|
||||
|
||||
|
||||
public void RenderLights(DeviceContext context, Camera camera, List<RenderableLODLights> lodlights)
|
||||
{
|
||||
//instanced rendering of all other lights, using appropriate shapes
|
||||
//blend mode: additive
|
||||
|
||||
|
||||
context.VertexShader.Set(LightVS);
|
||||
context.PixelShader.Set(LightPS);
|
||||
|
||||
LightVSVars.Vars.ViewProj = Matrix.Transpose(camera.ViewProjMatrix);
|
||||
LightVSVars.Vars.CameraPos = new Vector4(camera.Position, 0.0f);
|
||||
LightVSVars.Vars.LightType = 0;
|
||||
LightVSVars.Vars.IsLOD = 0;
|
||||
LightVSVars.Vars.Pad0 = 0;
|
||||
LightVSVars.Vars.Pad1 = 0;
|
||||
|
||||
//LightPSVars.Vars.GlobalLights = globalLights.Params;
|
||||
LightPSVars.Vars.ViewProjInv = Matrix.Transpose(camera.ViewProjInvMatrix);
|
||||
LightPSVars.Vars.CameraPos = new Vector4(camera.Position, 0.0f);
|
||||
LightPSVars.Vars.EnableShadows = 0;// (globalShadows != null) ? 1u : 0u;
|
||||
LightPSVars.Vars.RenderMode = 0;// rendermode;
|
||||
LightPSVars.Vars.RenderModeIndex = 1;// rendermodeind;
|
||||
LightPSVars.Vars.RenderSamplerCoord = 0;// (uint)RenderTextureSamplerCoord;
|
||||
LightPSVars.Vars.LightType = 0;
|
||||
LightPSVars.Vars.IsLOD = 0;
|
||||
LightPSVars.Vars.Pad0 = 0;
|
||||
LightPSVars.Vars.Pad1 = 0;
|
||||
|
||||
context.PixelShader.SetShaderResources(0, GBuffers.DepthSRV);
|
||||
context.PixelShader.SetShaderResources(2, GBuffers.SRVs);
|
||||
|
||||
//if (globalShadows != null)
|
||||
//{
|
||||
// globalShadows.SetFinalRenderResources(context);
|
||||
//}
|
||||
|
||||
|
||||
foreach (var rll in lodlights)
|
||||
{
|
||||
if (rll.PointsBuffer != null)
|
||||
{
|
||||
context.VertexShader.SetShaderResources(0, rll.PointsBuffer.SRV);
|
||||
context.PixelShader.SetShaderResources(6, rll.PointsBuffer.SRV);
|
||||
LightVSVars.Vars.LightType = 1;
|
||||
LightVSVars.Update(context);
|
||||
LightVSVars.SetVSCBuffer(context, 0);
|
||||
LightPSVars.Vars.LightType = 1;
|
||||
LightPSVars.Update(context);
|
||||
LightPSVars.SetPSCBuffer(context, 0);
|
||||
LightSphere.DrawInstanced(context, rll.PointsBuffer.StructCount);
|
||||
}
|
||||
if (rll.SpotsBuffer != null)
|
||||
{
|
||||
context.VertexShader.SetShaderResources(0, rll.SpotsBuffer.SRV);
|
||||
context.PixelShader.SetShaderResources(6, rll.SpotsBuffer.SRV);
|
||||
LightVSVars.Vars.LightType = 2;
|
||||
LightVSVars.Update(context);
|
||||
LightVSVars.SetVSCBuffer(context, 0);
|
||||
LightPSVars.Vars.LightType = 2;
|
||||
LightPSVars.Update(context);
|
||||
LightPSVars.SetPSCBuffer(context, 0);
|
||||
LightCone.DrawInstanced(context, rll.SpotsBuffer.StructCount);
|
||||
}
|
||||
if (rll.CapsBuffer != null)
|
||||
{
|
||||
context.VertexShader.SetShaderResources(0, rll.CapsBuffer.SRV);
|
||||
context.PixelShader.SetShaderResources(6, rll.CapsBuffer.SRV);
|
||||
LightVSVars.Vars.LightType = 4;
|
||||
LightVSVars.Update(context);
|
||||
LightVSVars.SetVSCBuffer(context, 0);
|
||||
LightPSVars.Vars.LightType = 4;
|
||||
LightPSVars.Update(context);
|
||||
LightPSVars.SetPSCBuffer(context, 0);
|
||||
LightCapsule.DrawInstanced(context, rll.CapsBuffer.StructCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
context.VertexShader.Set(null);
|
||||
context.PixelShader.Set(null);
|
||||
context.PixelShader.SetShaderResources(0, null, null, null);
|
||||
context.PixelShader.SetSamplers(0, null, null);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,7 @@ namespace CodeWalker.Rendering
|
||||
VertexShader pnctttxvs;
|
||||
VertexShader pncttxvs;
|
||||
PixelShader terrainps;
|
||||
PixelShader terrainpsdef;
|
||||
GpuVarsBuffer<TerrainShaderVSSceneVars> VSSceneVars;
|
||||
GpuVarsBuffer<TerrainShaderVSEntityVars> VSEntityVars;
|
||||
GpuVarsBuffer<TerrainShaderVSModelVars> VSModelVars;
|
||||
@@ -93,6 +94,7 @@ namespace CodeWalker.Rendering
|
||||
public int RenderTextureCoordIndex = 1;
|
||||
public int RenderTextureSamplerCoord = 1;
|
||||
public ShaderParamNames RenderTextureSampler = ShaderParamNames.DiffuseSampler;
|
||||
public bool Deferred = false;
|
||||
|
||||
private Dictionary<VertexType, InputLayout> layouts = new Dictionary<VertexType, InputLayout>();
|
||||
|
||||
@@ -107,6 +109,7 @@ namespace CodeWalker.Rendering
|
||||
byte[] vspnctttx = File.ReadAllBytes("Shaders\\TerrainVS_PNCTTTX.cso");
|
||||
byte[] vspncttx = File.ReadAllBytes("Shaders\\TerrainVS_PNCTTX.cso");
|
||||
byte[] psbytes = File.ReadAllBytes("Shaders\\TerrainPS.cso");
|
||||
byte[] psdefbytes = File.ReadAllBytes("Shaders\\TerrainPS_Deferred.cso");
|
||||
|
||||
pncctvs = new VertexShader(device, vspncct);
|
||||
pnccttvs = new VertexShader(device, vspncctt);
|
||||
@@ -116,6 +119,7 @@ namespace CodeWalker.Rendering
|
||||
pnctttxvs = new VertexShader(device, vspnctttx);
|
||||
pncttxvs = new VertexShader(device, vspncttx);
|
||||
terrainps = new PixelShader(device, psbytes);
|
||||
terrainpsdef = new PixelShader(device, psdefbytes);
|
||||
|
||||
VSSceneVars = new GpuVarsBuffer<TerrainShaderVSSceneVars>(device);
|
||||
VSEntityVars = new GpuVarsBuffer<TerrainShaderVSEntityVars>(device);
|
||||
@@ -259,7 +263,7 @@ namespace CodeWalker.Rendering
|
||||
|
||||
public override void SetShader(DeviceContext context)
|
||||
{
|
||||
context.PixelShader.Set(terrainps);
|
||||
context.PixelShader.Set(Deferred ? terrainpsdef : terrainps);
|
||||
}
|
||||
|
||||
public override bool SetInputLayout(DeviceContext context, VertexType type)
|
||||
@@ -639,6 +643,7 @@ namespace CodeWalker.Rendering
|
||||
PSGeomVars.Dispose();
|
||||
|
||||
terrainps.Dispose();
|
||||
terrainpsdef.Dispose();
|
||||
pncctvs.Dispose();
|
||||
pnccttvs.Dispose();
|
||||
pnccttxvs.Dispose();
|
||||
|
||||
@@ -59,8 +59,9 @@ namespace CodeWalker.Rendering
|
||||
{
|
||||
bool disposed = false;
|
||||
|
||||
VertexShader basicvs;
|
||||
PixelShader basicps;
|
||||
VertexShader vs;
|
||||
PixelShader ps;
|
||||
PixelShader psdef;
|
||||
GpuVarsBuffer<TreesLodShaderVSSceneVars> VSSceneVars;
|
||||
GpuVarsBuffer<TreesLodShaderVSEntityVars> VSEntityVars;
|
||||
GpuVarsBuffer<TreesLodShaderVSModelVars> VSModelVars;
|
||||
@@ -71,14 +72,18 @@ namespace CodeWalker.Rendering
|
||||
|
||||
private Dictionary<VertexType, InputLayout> layouts = new Dictionary<VertexType, InputLayout>();
|
||||
|
||||
public bool Deferred = false;
|
||||
|
||||
|
||||
public TreesLodShader(Device device)
|
||||
{
|
||||
byte[] vsbytes = File.ReadAllBytes("Shaders\\TreesLodVS.cso");
|
||||
byte[] psbytes = File.ReadAllBytes("Shaders\\TreesLodPS.cso");
|
||||
byte[] psdefbytes = File.ReadAllBytes("Shaders\\TreesLodPS_Deferred.cso");
|
||||
|
||||
basicvs = new VertexShader(device, vsbytes);
|
||||
basicps = new PixelShader(device, psbytes);
|
||||
vs = new VertexShader(device, vsbytes);
|
||||
ps = new PixelShader(device, psbytes);
|
||||
psdef = new PixelShader(device, psdefbytes);
|
||||
|
||||
VSSceneVars = new GpuVarsBuffer<TreesLodShaderVSSceneVars>(device);
|
||||
VSEntityVars = new GpuVarsBuffer<TreesLodShaderVSEntityVars>(device);
|
||||
@@ -112,8 +117,8 @@ namespace CodeWalker.Rendering
|
||||
|
||||
public override void SetShader(DeviceContext context)
|
||||
{
|
||||
context.VertexShader.Set(basicvs);
|
||||
context.PixelShader.Set(basicps);
|
||||
context.VertexShader.Set(vs);
|
||||
context.PixelShader.Set(Deferred ? psdef : ps);
|
||||
}
|
||||
|
||||
public override bool SetInputLayout(DeviceContext context, VertexType type)
|
||||
@@ -311,8 +316,9 @@ namespace CodeWalker.Rendering
|
||||
PSSceneVars.Dispose();
|
||||
PSEntityVars.Dispose();
|
||||
|
||||
basicps.Dispose();
|
||||
basicvs.Dispose();
|
||||
psdef.Dispose();
|
||||
ps.Dispose();
|
||||
vs.Dispose();
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ namespace CodeWalker.Rendering
|
||||
VertexShader vspnct;
|
||||
VertexShader vspnctx;
|
||||
PixelShader ps;
|
||||
PixelShader psdef;
|
||||
|
||||
GpuVarsBuffer<WaterShaderVSSceneVars> VSSceneVars;
|
||||
GpuVarsBuffer<WaterShaderVSEntityVars> VSEntityVars;
|
||||
@@ -107,6 +108,7 @@ namespace CodeWalker.Rendering
|
||||
public double CurrentRealTime = 0;
|
||||
public float CurrentElapsedTime = 0;
|
||||
public bool SpecularEnable = true;
|
||||
public bool Deferred = false;
|
||||
|
||||
|
||||
public RenderableTexture waterbump { get; set; }
|
||||
@@ -124,6 +126,7 @@ namespace CodeWalker.Rendering
|
||||
byte[] vspnctbytes = File.ReadAllBytes("Shaders\\WaterVS_PNCT.cso");
|
||||
byte[] vspnctxbytes = File.ReadAllBytes("Shaders\\WaterVS_PNCTX.cso");
|
||||
byte[] psbytes = File.ReadAllBytes("Shaders\\WaterPS.cso");
|
||||
byte[] psdefbytes = File.ReadAllBytes("Shaders\\WaterPS_Deferred.cso");
|
||||
|
||||
|
||||
vspt = new VertexShader(device, vsptbytes);
|
||||
@@ -131,6 +134,7 @@ namespace CodeWalker.Rendering
|
||||
vspnct = new VertexShader(device, vspnctbytes);
|
||||
vspnctx = new VertexShader(device, vspnctxbytes);
|
||||
ps = new PixelShader(device, psbytes);
|
||||
psdef = new PixelShader(device, psdefbytes);
|
||||
|
||||
VSSceneVars = new GpuVarsBuffer<WaterShaderVSSceneVars>(device);
|
||||
VSEntityVars = new GpuVarsBuffer<WaterShaderVSEntityVars>(device);
|
||||
@@ -213,7 +217,7 @@ namespace CodeWalker.Rendering
|
||||
|
||||
public override void SetShader(DeviceContext context)
|
||||
{
|
||||
context.PixelShader.Set(ps);
|
||||
context.PixelShader.Set(Deferred ? psdef : ps);
|
||||
}
|
||||
|
||||
public override bool SetInputLayout(DeviceContext context, VertexType type)
|
||||
@@ -552,6 +556,7 @@ namespace CodeWalker.Rendering
|
||||
PSGeomVars.Dispose();
|
||||
|
||||
ps.Dispose();
|
||||
psdef.Dispose();
|
||||
vspt.Dispose();
|
||||
vspct.Dispose();
|
||||
vspnct.Dispose();
|
||||
|
||||
@@ -421,4 +421,133 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
|
||||
|
||||
public class GpuMultiTexture //multiple texture and render targets (depth).
|
||||
{
|
||||
public Texture2D[] Textures;
|
||||
public Texture2D Depth;
|
||||
public RenderTargetView[] RTVs;
|
||||
public DepthStencilView DSV;
|
||||
public ShaderResourceView[] SRVs;
|
||||
public ShaderResourceView DepthSRV;
|
||||
public int VramUsage;
|
||||
public bool UseDepth;
|
||||
public int Count;
|
||||
|
||||
public void Init(Device device, int w, int h, int count, Format f, bool depth, Format df)
|
||||
{
|
||||
Count = count;
|
||||
VramUsage = 0;
|
||||
UseDepth = depth;
|
||||
ResourceUsage u = ResourceUsage.Default;
|
||||
BindFlags b = BindFlags.RenderTarget | BindFlags.ShaderResource;
|
||||
RenderTargetViewDimension rtvd = RenderTargetViewDimension.Texture2D;
|
||||
ShaderResourceViewDimension srvd = ShaderResourceViewDimension.Texture2D;// D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
int fs = DXUtility.ElementSize(f);
|
||||
int wh = w * h;
|
||||
BindFlags db = BindFlags.DepthStencil | BindFlags.ShaderResource;// D3D11_BIND_DEPTH_STENCIL;
|
||||
DepthStencilViewDimension dsvd = DepthStencilViewDimension.Texture2D;
|
||||
|
||||
Textures = new Texture2D[count];
|
||||
RTVs = new RenderTargetView[count];
|
||||
SRVs = new ShaderResourceView[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Textures[i] = DXUtility.CreateTexture2D(device, w, h, 1, 1, f, 1, 0, u, b, 0, 0);
|
||||
RTVs[i] = DXUtility.CreateRenderTargetView(device, Textures[i], f, rtvd, 0, 0, 0);
|
||||
SRVs[i] = DXUtility.CreateShaderResourceView(device, Textures[i], f, srvd, 1, 0, 0, 0);
|
||||
VramUsage += (wh * fs);
|
||||
}
|
||||
if (depth)
|
||||
{
|
||||
Format dtexf = Format.R32_Typeless;
|
||||
Format dsrvf = Format.R32_Float;
|
||||
switch (df)
|
||||
{
|
||||
case Format.D16_UNorm:
|
||||
dtexf = Format.R16_Typeless;
|
||||
dsrvf = Format.R16_UNorm;
|
||||
break;
|
||||
case Format.D24_UNorm_S8_UInt:
|
||||
dtexf = Format.R24G8_Typeless;
|
||||
dsrvf = Format.R24_UNorm_X8_Typeless;
|
||||
break;
|
||||
case Format.D32_Float:
|
||||
dtexf = Format.R32_Typeless;
|
||||
dsrvf = Format.R32_Float;
|
||||
break;
|
||||
case Format.D32_Float_S8X24_UInt:
|
||||
dtexf = Format.R32G8X24_Typeless;//is this right? who uses this anyway??
|
||||
dsrvf = Format.R32_Float_X8X24_Typeless;
|
||||
break;
|
||||
}
|
||||
|
||||
Depth = DXUtility.CreateTexture2D(device, w, h, 1, 1, dtexf, 1, 0, u, db, 0, 0);
|
||||
DSV = DXUtility.CreateDepthStencilView(device, Depth, df, dsvd);
|
||||
DepthSRV = DXUtility.CreateShaderResourceView(device, Depth, dsrvf, srvd, 1, 0, 0, 0);
|
||||
VramUsage += (wh * DXUtility.ElementSize(df));
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
SRVs[i].Dispose();
|
||||
RTVs[i].Dispose();
|
||||
Textures[i].Dispose();
|
||||
}
|
||||
SRVs = null;
|
||||
RTVs = null;
|
||||
Textures = null;
|
||||
|
||||
if (DSV != null)
|
||||
{
|
||||
DSV.Dispose();
|
||||
DSV = null;
|
||||
}
|
||||
if (DepthSRV != null)
|
||||
{
|
||||
DepthSRV.Dispose();
|
||||
DepthSRV = null;
|
||||
}
|
||||
if (Depth != null)
|
||||
{
|
||||
Depth.Dispose();
|
||||
Depth = null;
|
||||
}
|
||||
}
|
||||
public GpuMultiTexture(Device device, int w, int h, int count, Format f, bool depth, Format df)
|
||||
{
|
||||
Init(device, w, h, count, f, depth, df);
|
||||
}
|
||||
public GpuMultiTexture(Device device, int w, int h, int count, Format f)
|
||||
{
|
||||
Init(device, w, h, count, f, false, Format.Unknown);
|
||||
}
|
||||
|
||||
public void Clear(DeviceContext context, Color4 colour)
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
context.ClearRenderTargetView(RTVs[i], colour);
|
||||
}
|
||||
if (UseDepth)
|
||||
{
|
||||
context.ClearDepthStencilView(DSV, DepthStencilClearFlags.Depth, 0.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearDepth(DeviceContext context)
|
||||
{
|
||||
if (!UseDepth) return;
|
||||
context.ClearDepthStencilView(DSV, DepthStencilClearFlags.Depth, 0.0f, 0);
|
||||
}
|
||||
|
||||
public void SetRenderTargets(DeviceContext context)
|
||||
{
|
||||
context.OutputMerger.SetRenderTargets(UseDepth ? DSV : null, RTVs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
public UnitCapsule(Device device, byte[] vsbytes, int detail)
|
||||
public UnitCapsule(Device device, byte[] vsbytes, int detail, bool invert = false)
|
||||
{
|
||||
|
||||
InputLayout = new InputLayout(device, vsbytes, new[]
|
||||
@@ -208,8 +208,8 @@ namespace CodeWalker.Rendering
|
||||
foreach (var tri in curtris)
|
||||
{
|
||||
idata.Add((uint)tri.v1);
|
||||
idata.Add((uint)tri.v2);
|
||||
idata.Add((uint)tri.v3);
|
||||
idata.Add((uint)(invert ? tri.v3 : tri.v2));
|
||||
idata.Add((uint)(invert ? tri.v2 : tri.v3));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SharpDX;
|
||||
using SharpDX.Direct3D;
|
||||
using SharpDX.Direct3D11;
|
||||
using Device = SharpDX.Direct3D11.Device;
|
||||
using Buffer = SharpDX.Direct3D11.Buffer;
|
||||
using SharpDX.DXGI;
|
||||
|
||||
namespace CodeWalker.Rendering
|
||||
{
|
||||
public class UnitCone
|
||||
{
|
||||
private Buffer VertexBuffer { get; set; }
|
||||
private Buffer IndexBuffer { get; set; }
|
||||
private InputLayout InputLayout { get; set; }
|
||||
private VertexBufferBinding vbbinding;
|
||||
private int indexcount;
|
||||
|
||||
private struct SphTri
|
||||
{
|
||||
public int v1;
|
||||
public int v2;
|
||||
public int v3;
|
||||
public SphTri(int i1, int i2, int i3)
|
||||
{
|
||||
v1 = i1;
|
||||
v2 = i2;
|
||||
v3 = i3;
|
||||
}
|
||||
}
|
||||
|
||||
public UnitCone(Device device, byte[] vsbytes, int detail, bool invert = false)
|
||||
{
|
||||
|
||||
InputLayout = new InputLayout(device, vsbytes, new[]
|
||||
{
|
||||
new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
|
||||
new InputElement("NORMAL", 0, Format.R32G32B32A32_Float, 16, 0),
|
||||
});
|
||||
|
||||
|
||||
|
||||
List<Vector4> verts = new List<Vector4>();
|
||||
Dictionary<Vector4, int> vdict = new Dictionary<Vector4, int>();
|
||||
List<SphTri> curtris = new List<SphTri>();
|
||||
|
||||
verts.Add(new Vector4(0.0f, 0.0f, 0.0f, 0.0f));//top end (translated by VS!)
|
||||
verts.Add(new Vector4(0.0f, -1.0f, 0.0f, 0.0f));//top normal
|
||||
verts.Add(new Vector4(0.0f, 0.0f, 0.0f, 1.0f));//bottom end
|
||||
verts.Add(new Vector4(0.0f, 1.0f, 0.0f, 1.0f));//bottom normal
|
||||
|
||||
int nlons = detail * 4;
|
||||
int lastlon = nlons - 1;
|
||||
float latrng = 1.0f / (detail);
|
||||
float lonrng = 1.0f / (nlons);
|
||||
float twopi = (float)(2.0 * Math.PI);
|
||||
|
||||
for (int lon = 0; lon < nlons; lon++)
|
||||
{
|
||||
float tlon = lon * lonrng;
|
||||
float rlon = tlon * twopi;
|
||||
float lonx = (float)Math.Sin(rlon);
|
||||
float lonz = (float)Math.Cos(rlon);
|
||||
|
||||
verts.Add(new Vector4(lonx, 0.0f, lonz, 1.0f));//2
|
||||
verts.Add(new Vector4(lonx, 0.0f, lonz, 0.0f));//side normal
|
||||
verts.Add(new Vector4(lonx, 0.0f, lonz, 1.0f));//3
|
||||
verts.Add(new Vector4(0.0f, 1.0f, 0.0f, 0.0f));//bottom normal
|
||||
}
|
||||
|
||||
for (int lon = 0; lon < nlons; lon++)
|
||||
{
|
||||
int i0 = 2 + lon * 2;
|
||||
int i1 = i0 + 2;
|
||||
|
||||
if (lon == lastlon)
|
||||
{
|
||||
i1 = 2;
|
||||
}
|
||||
|
||||
curtris.Add(new SphTri(0, i0, i1)); //fill the cone
|
||||
curtris.Add(new SphTri(1, i1+1, i0+1)); //bottom cap triangles
|
||||
}
|
||||
|
||||
|
||||
|
||||
List<uint> idata = new List<uint>();
|
||||
foreach (var tri in curtris)
|
||||
{
|
||||
idata.Add((uint)tri.v1);
|
||||
idata.Add((uint)(invert ? tri.v2 : tri.v3));
|
||||
idata.Add((uint)(invert ? tri.v3 : tri.v2));
|
||||
}
|
||||
|
||||
|
||||
VertexBuffer = Buffer.Create(device, BindFlags.VertexBuffer, verts.ToArray());
|
||||
vbbinding = new VertexBufferBinding(VertexBuffer, 32, 0);
|
||||
|
||||
IndexBuffer = Buffer.Create(device, BindFlags.IndexBuffer, idata.ToArray());
|
||||
indexcount = idata.Count;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void Draw(DeviceContext context)
|
||||
{
|
||||
context.InputAssembler.InputLayout = InputLayout;
|
||||
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
|
||||
context.InputAssembler.SetVertexBuffers(0, vbbinding);
|
||||
context.InputAssembler.SetIndexBuffer(IndexBuffer, Format.R32_UInt, 0);
|
||||
|
||||
context.DrawIndexed(indexcount, 0, 0);
|
||||
}
|
||||
|
||||
public void DrawInstanced(DeviceContext context, int count)
|
||||
{
|
||||
context.InputAssembler.InputLayout = InputLayout;
|
||||
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
|
||||
context.InputAssembler.SetVertexBuffers(0, vbbinding);
|
||||
context.InputAssembler.SetIndexBuffer(IndexBuffer, Format.R32_UInt, 0);
|
||||
|
||||
context.DrawIndexedInstanced(indexcount, count, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (VertexBuffer != null)
|
||||
{
|
||||
VertexBuffer.Dispose();
|
||||
VertexBuffer = null;
|
||||
}
|
||||
if (IndexBuffer != null)
|
||||
{
|
||||
IndexBuffer.Dispose();
|
||||
IndexBuffer = null;
|
||||
}
|
||||
if (InputLayout != null)
|
||||
{
|
||||
InputLayout.Dispose();
|
||||
InputLayout = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
public UnitSphere(Device device, byte[] vsbytes, int detail)
|
||||
public UnitSphere(Device device, byte[] vsbytes, int detail, bool invert = false)
|
||||
{
|
||||
|
||||
InputLayout = new InputLayout(device, vsbytes, new[]
|
||||
@@ -121,8 +121,8 @@ namespace CodeWalker.Rendering
|
||||
foreach (var tri in curtris)
|
||||
{
|
||||
idata.Add((uint)tri.v1);
|
||||
idata.Add((uint)tri.v2);
|
||||
idata.Add((uint)tri.v3);
|
||||
idata.Add((uint)(invert ? tri.v3 : tri.v2));
|
||||
idata.Add((uint)(invert ? tri.v2 : tri.v3));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user