Render voxels with an approximately-correct z-offset.

This commit is contained in:
Paul Chote
2016-08-09 10:15:44 +01:00
parent c312cf9171
commit f0306e7cc2
4 changed files with 50 additions and 12 deletions

View File

@@ -22,9 +22,9 @@ namespace OpenRA.Graphics
public readonly Sprite Sprite;
public readonly Sprite ShadowSprite;
public readonly float ShadowDirection;
public readonly float2[] ProjectedShadowBounds;
public readonly float3[] ProjectedShadowBounds;
public VoxelRenderProxy(Sprite sprite, Sprite shadowSprite, float2[] projectedShadowBounds, float shadowDirection)
public VoxelRenderProxy(Sprite sprite, Sprite shadowSprite, float3[] projectedShadowBounds, float shadowDirection)
{
Sprite = sprite;
ShadowSprite = shadowSprite;
@@ -145,7 +145,7 @@ namespace OpenRA.Graphics
var shadowScreenTransform = Util.MatrixMultiply(cameraTransform, invShadowTransform);
var shadowGroundNormal = Util.MatrixVectorMultiply(shadowTransform, groundNormal);
var screenCorners = new float2[4];
var screenCorners = new float3[4];
for (var j = 0; j < 4; j++)
{
// Project to ground plane
@@ -154,7 +154,7 @@ namespace OpenRA.Graphics
// Rotate to camera-space
corners[j] = Util.MatrixVectorMultiply(shadowScreenTransform, corners[j]);
screenCorners[j] = new float2(corners[j][0], corners[j][1]);
screenCorners[j] = new float3(corners[j][0], corners[j][1], 0);
}
// Shadows are rendered at twice the resolution to reduce artifacts

View File

@@ -126,7 +126,10 @@ namespace OpenRA.Graphics
return;
if (devTrait.Value != null)
{
Game.Renderer.WorldSpriteRenderer.SetDepthPreviewEnabled(devTrait.Value.ShowDepthPreview);
Game.Renderer.WorldRgbaSpriteRenderer.SetDepthPreviewEnabled(devTrait.Value.ShowDepthPreview);
}
RefreshPalette();

View File

@@ -14,6 +14,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.Graphics
{
@@ -107,7 +108,12 @@ namespace OpenRA.Mods.Common.Graphics
{
var groundPos = voxel.pos - new WVec(0, 0, wr.World.Map.DistanceAboveTerrain(voxel.pos).Length);
var groundZ = wr.World.Map.Grid.TileSize.Height * (groundPos.Z - voxel.pos.Z) / 1024f;
var pxOrigin = wr.ScreenPosition(voxel.pos);
var pxOrigin = wr.Screen3DPosition(voxel.pos);
// HACK: We don't have enough texture channels to pass the depth data to the shader
// so for now just offset everything forward so that the back corner is rendered at pos.
pxOrigin -= new float3(0, 0, Screen3DBounds(wr).Second.X);
var shadowOrigin = pxOrigin - groundZ * (new float2(renderProxy.ShadowDirection, 1));
var psb = renderProxy.ProjectedShadowBounds;
@@ -135,12 +141,13 @@ namespace OpenRA.Mods.Common.Graphics
var c = Color.Purple;
var psb = renderProxy.ProjectedShadowBounds;
// TODO: add float3 support to WorldRgbaColorRenderer
Game.Renderer.WorldRgbaColorRenderer.DrawPolygon(new[]
{
shadowOrigin + psb[1],
shadowOrigin + psb[3],
shadowOrigin + psb[0],
shadowOrigin + psb[2]
shadowOrigin + psb[1].XY,
shadowOrigin + psb[3].XY,
shadowOrigin + psb[0].XY,
shadowOrigin + psb[2].XY
}, iz, c);
// Draw voxel bounding box
@@ -190,6 +197,11 @@ namespace OpenRA.Mods.Common.Graphics
}
public Rectangle ScreenBounds(WorldRenderer wr)
{
return Screen3DBounds(wr).First;
}
Pair<Rectangle, float2> Screen3DBounds(WorldRenderer wr)
{
var pxOrigin = wr.ScreenPosition(voxel.pos);
var draw = voxel.voxels.Where(v => v.DisableFunc == null || !v.DisableFunc());
@@ -198,8 +210,11 @@ namespace OpenRA.Mods.Common.Graphics
var minX = float.MaxValue;
var minY = float.MaxValue;
var minZ = float.MaxValue;
var maxX = float.MinValue;
var maxY = float.MinValue;
var maxZ = float.MinValue;
foreach (var v in draw)
{
var bounds = v.Voxel.Bounds(v.FrameFunc());
@@ -208,7 +223,7 @@ namespace OpenRA.Mods.Common.Graphics
float sx, sy, sz;
wr.ScreenVectorComponents(v.OffsetFunc(), out sx, out sy, out sz);
var pxPos = pxOrigin + new float2(sx, sy);
var pxPos = pxOrigin + new float3(sx, sy, sz);
var screenTransform = OpenRA.Graphics.Util.MatrixMultiply(cameraTransform, worldTransform);
for (var i = 0; i < 8; i++)
@@ -217,12 +232,14 @@ namespace OpenRA.Mods.Common.Graphics
var screen = OpenRA.Graphics.Util.MatrixVectorMultiply(screenTransform, vec);
minX = Math.Min(minX, pxPos.X + screen[0]);
minY = Math.Min(minY, pxPos.Y + screen[1]);
minZ = Math.Min(minZ, pxPos.Z + screen[2]);
maxX = Math.Max(maxX, pxPos.X + screen[0]);
maxY = Math.Max(maxY, pxPos.Y + screen[1]);
maxZ = Math.Max(minZ, pxPos.Z + screen[2]);
}
}
return Rectangle.FromLTRB((int)minX, (int)minY, (int)maxX, (int)maxY);
return Pair.New(Rectangle.FromLTRB((int)minX, (int)minY, (int)maxX, (int)maxY), new float2(minZ, maxZ));
}
}
}

View File

@@ -1,7 +1,25 @@
uniform sampler2D DiffuseTexture;
uniform bool EnableDepthPreview;
varying vec4 vTexCoord;
void main()
{
gl_FragColor = texture2D(DiffuseTexture, vTexCoord.st);
vec4 c = texture2D(DiffuseTexture, vTexCoord.st);
// Discard any transparent fragments (both color and depth)
if (c.a == 0.0)
discard;
float depth = gl_FragCoord.z;
// Convert to window coords
gl_FragDepth = 0.5 * depth + 0.5;
if (EnableDepthPreview)
{
// Front of the depth buffer is at 0, but we want to render it as bright
gl_FragColor = vec4(vec3(1.0 - gl_FragDepth), 1.0);
}
else
gl_FragColor = c;
}