Merge pull request #11058 from pchote/terrain-vertex-depth

Use vertex depths for rendering terrain depth preview.
This commit is contained in:
reaperrr
2016-04-10 16:13:50 +02:00
17 changed files with 169 additions and 36 deletions

View File

@@ -508,6 +508,26 @@ namespace OpenRA
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(float3))
{
if (value != null)
{
var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
float x = 0;
float y = 0;
float z = 0;
float.TryParse(parts[0], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out x);
float.TryParse(parts[1], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out y);
// z component is optional for compatibility with older float2 definitions
if (parts.Length > 2)
float.TryParse(parts[2], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out z);
return new float3(x, y, z);
}
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(Rectangle))
{
if (value != null)

View File

@@ -359,6 +359,9 @@ namespace OpenRA
ModData.InitializeLoaders(ModData.DefaultFileSystem);
Renderer.InitializeFonts(ModData);
var grid = ModData.Manifest.Contains<MapGrid>() ? ModData.Manifest.Get<MapGrid>() : null;
Renderer.InitializeDepthBuffer(grid);
if (Cursor != null)
Cursor.Dispose();

View File

@@ -95,6 +95,7 @@ namespace OpenRA
void SetBool(string name, bool value);
void SetVec(string name, float x);
void SetVec(string name, float x, float y);
void SetVec(string name, float x, float y, float z);
void SetVec(string name, float[] vec, int length);
void SetTexture(string param, ITexture texture);
void SetMatrix(string param, float[] mtx);

View File

@@ -114,11 +114,17 @@ namespace OpenRA.Graphics
shader.SetTexture("Palette", palette);
}
public void SetViewportParams(Size screen, float zoom, int2 scroll)
public void SetViewportParams(Size screen, float depthScale, float depthOffset, float zoom, int2 scroll)
{
shader.SetVec("Scroll", scroll.X, scroll.Y);
shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height);
shader.SetVec("r2", -1, 1);
shader.SetVec("Scroll", scroll.X, scroll.Y, scroll.Y);
shader.SetVec("r1",
zoom * 2f / screen.Width,
-zoom * 2f / screen.Height,
-depthScale * zoom / screen.Height);
shader.SetVec("r2", -1, 1, 1 - depthOffset);
// Texture index is sampled as a float, so convert to pixels then scale
shader.SetVec("DepthTextureScale", 128 * depthScale * zoom / screen.Height);
}
public void SetDepthPreviewEnabled(bool enabled)

View File

@@ -68,12 +68,15 @@ namespace OpenRA.Graphics
public void Update(CPos cell, Sprite sprite)
{
var pos = sprite == null ? float2.Zero :
var xy = sprite == null ? float2.Zero :
worldRenderer.ScreenPosition(map.CenterOfCell(cell)) + sprite.Offset - 0.5f * sprite.Size;
Update(cell.ToMPos(map.Grid.Type), sprite, pos);
// TODO: Deal with sprite z offsets
var z = worldRenderer.ScreenZPosition(map.CenterOfCell(cell), 0);
Update(cell.ToMPos(map.Grid.Type), sprite, new float3(xy.X, xy.Y, z));
}
public void Update(MPos uv, Sprite sprite, float2 pos)
public void Update(MPos uv, Sprite sprite, float3 pos)
{
if (sprite != null)
{

View File

@@ -21,15 +21,15 @@ namespace OpenRA.Graphics
static readonly int[] ChannelMasks = { 2, 1, 0, 3 };
static readonly float[] ChannelSelect = { 0.2f, 0.4f, 0.6f, 0.8f };
public static void FastCreateQuad(Vertex[] vertices, float2 o, Sprite r, float paletteTextureIndex, int nv, float2 size)
public static void FastCreateQuad(Vertex[] vertices, float3 o, Sprite r, float paletteTextureIndex, int nv, float3 size)
{
var b = new float2(o.X + size.X, o.Y);
var c = new float2(o.X + size.X, o.Y + size.Y);
var d = new float2(o.X, o.Y + size.Y);
var b = new float3(o.X + size.X, o.Y, o.Z);
var c = new float3(o.X + size.X, o.Y + size.Y, o.Z + size.Z);
var d = new float3(o.X, o.Y + size.Y, o.Z + size.Z);
FastCreateQuad(vertices, o, b, c, d, r, paletteTextureIndex, nv);
}
public static void FastCreateQuad(Vertex[] vertices, float2 a, float2 b, float2 c, float2 d, Sprite r, float paletteTextureIndex, int nv)
public static void FastCreateQuad(Vertex[] vertices, float3 a, float3 b, float3 c, float3 d, Sprite r, float paletteTextureIndex, int nv)
{
var attribC = ChannelSelect[(int)r.Channel];
if (r.Sheet.Type == SheetType.DualIndexed)

View File

@@ -18,11 +18,8 @@ namespace OpenRA.Graphics
{
public readonly float X, Y, Z, U, V, P, C;
public Vertex(float2 xy, float u, float v, float p, float c)
: this(xy.X, xy.Y, 0, u, v, p, c) { }
public Vertex(float[] xyz, float u, float v, float p, float c)
: this(xyz[0], xyz[1], xyz[2], u, v, p, c) { }
public Vertex(float3 xyz, float u, float v, float p, float c)
: this(xyz.X, xyz.Y, xyz.Z, u, v, p, c) { }
public Vertex(float x, float y, float z, float u, float v, float p, float c)
{

View File

@@ -71,7 +71,7 @@ namespace OpenRA.Graphics
sheetBuilder = CreateSheetBuilder();
}
Vertex[] GenerateSlicePlane(int su, int sv, Func<int, int, VxlElement> first, Func<int, int, VxlElement> second, Func<int, int, float[]> coord)
Vertex[] GenerateSlicePlane(int su, int sv, Func<int, int, VxlElement> first, Func<int, int, VxlElement> second, Func<int, int, float3> coord)
{
var colors = new byte[su * sv];
var normals = new byte[su * sv];
@@ -158,21 +158,21 @@ namespace OpenRA.Graphics
yield return GenerateSlicePlane(l.Size[1], l.Size[2],
(u, v) => get(x, u, v),
(u, v) => get(x - 1, u, v),
(u, v) => new float[] { x, u, v });
(u, v) => new float3(x, u, v));
for (var y = 0; y <= l.Size[1]; y++)
if (yPlanes[y])
yield return GenerateSlicePlane(l.Size[0], l.Size[2],
(u, v) => get(u, y, v),
(u, v) => get(u, y - 1, v),
(u, v) => new float[] { u, y, v });
(u, v) => new float3(u, y, v));
for (var z = 0; z <= l.Size[2]; z++)
if (zPlanes[z])
yield return GenerateSlicePlane(l.Size[0], l.Size[1],
(u, v) => get(u, v, z),
(u, v) => get(u, v, z - 1),
(u, v) => new float[] { u, v, z });
(u, v) => new float3(u, v, z));
}
public VoxelRenderData GenerateRenderData(VxlLimb l)

View File

@@ -28,6 +28,8 @@ namespace OpenRA
public readonly int MaximumTileSearchRange = 50;
public readonly bool EnableDepthBuffer = false;
public readonly WVec[] SubCellOffsets =
{
new WVec(0, 0, 0), // full cell - index 0

View File

@@ -254,6 +254,7 @@
<Compile Include="Traits\Player\IndexedPlayerPalette.cs" />
<Compile Include="Traits\ActivityUtils.cs" />
<Compile Include="FileSystem\ZipFolder.cs" />
<Compile Include="Primitives\float3.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="FileSystem\D2kSoundResources.cs" />

View File

@@ -0,0 +1,54 @@
#region Copyright & License Information
/*
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Runtime.InteropServices;
namespace OpenRA
{
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "Mimic a built-in type alias.")]
[StructLayout(LayoutKind.Sequential)]
public struct float3
{
public readonly float X, Y, Z;
public float2 XY { get { return new float2(X, Y); } }
public float3(float x, float y, float z) { X = x; Y = y; Z = z; }
public float3(float2 xy, float z) { X = xy.X; Y = xy.Y; Z = z; }
public static implicit operator float3(int2 src) { return new float3(src.X, src.Y, 0); }
public static implicit operator float3(float2 src) { return new float3(src.X, src.Y, 0); }
public static float3 operator +(float3 a, float3 b) { return new float3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); }
public static float3 operator -(float3 a, float3 b) { return new float3(a.X - b.X, a.Y - b.Y, a.Z - b.Z); }
public static float3 operator -(float3 a) { return new float3(-a.X, -a.Y, -a.Z); }
public static float3 operator *(float3 a, float3 b) { return new float3(a.X * b.X, a.Y * b.Y, a.Z * b.Z); }
public static float3 operator *(float a, float3 b) { return new float3(a * b.X, a * b.Y, a * b.Z); }
public static float3 operator /(float3 a, float3 b) { return new float3(a.X / b.X, a.Y / b.Y, a.Z / b.Z); }
public static float3 operator /(float3 a, float b) { return new float3(a.X / b, a.Y / b, a.Z / b); }
public static bool operator ==(float3 me, float3 other) { return me.X == other.X && me.Y == other.Y && me.Z == other.Z; }
public static bool operator !=(float3 me, float3 other) { return !(me == other); }
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); }
public override bool Equals(object obj)
{
var o = obj as float3?;
return o != null && o == this;
}
public override string ToString() { return "{0},{1},{2}".F(X, Y, Z); }
public static readonly float3 Zero = new float3(0, 0, 0);
}
}

View File

@@ -40,6 +40,9 @@ namespace OpenRA
SheetBuilder fontSheetBuilder;
float depthScale;
float depthOffset;
Size? lastResolution;
int2? lastScroll;
float? lastZoom;
@@ -102,6 +105,20 @@ namespace OpenRA
}
}
public void InitializeDepthBuffer(MapGrid mapGrid)
{
// The depth buffer needs to be initialized with enough range to cover:
// - the height of the screen
// - the z-offset of tiles from MaxTerrainHeight below the bottom of the screen (pushed into view)
// - additional z-offset from actors on top of MaxTerrainHeight terrain
// - a small margin so that tiles rendered partially above the top edge of the screen aren't pushed behind the clip plane
// We need an offset of mapGrid.MaximumTerrainHeight * mapGrid.TileSize.Height / 2 to cover the terrain height
// and choose to use mapGrid.MaximumTerrainHeight * mapGrid.TileSize.Height / 4 for each of the actor and top-edge cases
this.depthScale = mapGrid == null || !mapGrid.EnableDepthBuffer ? 0 :
(float)Resolution.Height / (Resolution.Height + mapGrid.TileSize.Height * mapGrid.MaximumTerrainHeight);
this.depthOffset = this.depthScale / 2;
}
public void BeginFrame(int2 scroll, float zoom)
{
Device.Clear();
@@ -115,8 +132,8 @@ namespace OpenRA
if (resolutionChanged)
{
lastResolution = Resolution;
RgbaSpriteRenderer.SetViewportParams(Resolution, 1f, int2.Zero);
SpriteRenderer.SetViewportParams(Resolution, 1f, int2.Zero);
RgbaSpriteRenderer.SetViewportParams(Resolution, 0f, 0f, 1f, int2.Zero);
SpriteRenderer.SetViewportParams(Resolution, 0f, 0f, 1f, int2.Zero);
RgbaColorRenderer.SetViewportParams(Resolution, 1f, int2.Zero);
}
@@ -125,8 +142,8 @@ namespace OpenRA
{
lastScroll = scroll;
lastZoom = zoom;
WorldRgbaSpriteRenderer.SetViewportParams(Resolution, zoom, scroll);
WorldSpriteRenderer.SetViewportParams(Resolution, zoom, scroll);
WorldRgbaSpriteRenderer.SetViewportParams(Resolution, depthScale, depthOffset, zoom, scroll);
WorldSpriteRenderer.SetViewportParams(Resolution, depthScale, depthOffset, zoom, scroll);
WorldVoxelRenderer.SetViewportParams(Resolution, zoom, scroll);
WorldRgbaColorRenderer.SetViewportParams(Resolution, zoom, scroll);
}

View File

@@ -215,6 +215,9 @@ namespace OpenRA.Platforms.Default
public delegate void Uniform2f(int location, float v0, float v1);
public static Uniform2f glUniform2f { get; private set; }
public delegate void Uniform3f(int location, float v0, float v1, float v2);
public static Uniform3f glUniform3f { get; private set; }
public delegate void Uniform1fv(int location, int count, IntPtr value);
public static Uniform1fv glUniform1fv { get; private set; }
@@ -395,6 +398,7 @@ namespace OpenRA.Platforms.Default
glUniform1i = Bind<Uniform1i>("glUniform1i");
glUniform1f = Bind<Uniform1f>("glUniform1f");
glUniform2f = Bind<Uniform2f>("glUniform2f");
glUniform3f = Bind<Uniform3f>("glUniform3f");
glUniform1fv = Bind<Uniform1fv>("glUniform1fv");
glUniform2fv = Bind<Uniform2fv>("glUniform2fv");
glUniform3fv = Bind<Uniform3fv>("glUniform3fv");

View File

@@ -189,6 +189,17 @@ namespace OpenRA.Platforms.Default
OpenGL.CheckGLError();
}
public void SetVec(string name, float x, float y, float z)
{
VerifyThreadAffinity();
OpenGL.glUseProgram(program);
OpenGL.CheckGLError();
var param = OpenGL.glGetUniformLocation(program, name);
OpenGL.CheckGLError();
OpenGL.glUniform3f(param, x, y, z);
OpenGL.CheckGLError();
}
public void SetVec(string name, float[] vec, int length)
{
VerifyThreadAffinity();

View File

@@ -1,5 +1,5 @@
uniform vec2 Scroll;
uniform vec2 r1, r2;
uniform vec3 Scroll;
uniform vec3 r1, r2;
attribute vec4 aVertexPosition;
attribute vec4 aVertexTexCoord;
@@ -7,7 +7,6 @@ varying vec4 vTexCoord;
void main()
{
vec2 p = (aVertexPosition.xy - Scroll.xy)*r1 + r2;
gl_Position = vec4(p.x,p.y,0,1);
gl_Position = vec4((aVertexPosition.xyz - Scroll.xyz) * r1 + r2, 1);
vTexCoord = aVertexTexCoord;
}

View File

@@ -1,6 +1,7 @@
uniform sampler2D DiffuseTexture, Palette;
uniform bool EnableDepthPreview;
uniform float DepthTextureScale;
varying vec4 vTexCoord;
varying vec4 vChannelMask;
@@ -18,8 +19,23 @@ void main()
if (EnableDepthPreview && length(vDepthMask) > 0.0)
{
if (abs(DepthTextureScale) > 0.0)
{
// Preview vertex aware depth
float depth = gl_FragCoord.z + DepthTextureScale * dot(x, vDepthMask);
// Convert to window coords
depth = 0.5 * depth + 0.5;
// Front of the depth buffer is at 0, but we want to render it as bright
gl_FragColor = vec4(vec3(1.0 - depth), 1.0);
}
else
{
// Preview boring sprite-only depth
float depth = dot(x, vDepthMask);
gl_FragColor = vec4(depth, depth, depth, 1);
gl_FragColor = vec4(depth, depth, depth, 1.0);
}
}
else
gl_FragColor = c;

View File

@@ -1,5 +1,5 @@
uniform vec2 Scroll;
uniform vec2 r1,r2; // matrix elements
uniform vec3 Scroll;
uniform vec3 r1, r2;
attribute vec4 aVertexPosition;
attribute vec4 aVertexTexCoord;
@@ -36,8 +36,7 @@ vec4 DecodeDepthChannelMask(float x)
void main()
{
vec2 p = (aVertexPosition.xy - Scroll.xy) * r1 + r2;
gl_Position = vec4(p.x,p.y,0,1);
gl_Position = vec4((aVertexPosition.xyz - Scroll.xyz) * r1 + r2, 1);
vTexCoord = aVertexTexCoord;
vChannelMask = DecodeChannelMask(aVertexTexCoord.w);
vDepthMask = DecodeDepthChannelMask(aVertexTexCoord.w);