Hey everyone,

What started out as a trivial implementation of JME3 features has shaped up into a bit of an experiment. I’ve been playing around with the existing JME3 shaders and render buffers, and have created a vertical mirror effect and a ray-based shadow engine. I might look into committing the changes later, but there’s still a lot of work to be done.

The room and furniture are all from a hotel room project on SketchUp, which has a BSD-ish license for use of the work. It can be found here.

So, the screenshots:

Trying again

Image collapsed to save space

Image collapsed to save space

http://i.imgur.com/FG4cV.png

http://i.imgur.com/3HGgW.png

very nice, how are the performances compared to built in shadows?

@nehon said:

very nice, how are the performances compared to built in shadows?

It does not seem to have any noticeable difference compared to shadowless rendering and hence is orders of magnitude more efficient than the built in shadow mapper. This is probably because it does not use textures and does not require any loops to work. However, it lacks the ubiquity of a texture-based shadow renderer because it is designed for very specific applications such as hallways, doorways... it can be implemented in indoor scenes, cities, or anywhere there are a lot of rectangular shapes or apertures. Still, that can take a considerable load off the GPU and offer a superior effect for the specific applications mentioned. It also works with point lights.

Here is the code on the shader side for the vector shadows, added to the regular JME3 normal mapping shader:

[java]

float calcLateral(vec2 xzLine, vec2 yzLine, vec3 offsetPos, vec3 place, vec3 m_gradPos1, vec3 m_gradPos2, float soften,

vec2 m_shadow1Vec1, vec2 m_shadow1Vec2)

{

float blue = 0.0f;

if (xzLine.x < m_shadow1Vec1.x)

{

offsetPos = vec3(place.x - m_gradPos1.x,place.y - m_gradPos1.y,place.z - m_gradPos1.z);

xzLine = normalize(offsetPos.xz);

yzLine = normalize(offsetPos.yz);

if (xzLine.x > m_shadow1Vec1.x -soften && xzLine.x < m_shadow1Vec2.x)

{

{

blue = (xzLine.x + soften - m_shadow1Vec1.x)/soften;

if (blue > 1.0f)

return 1.0f;

}

}

}

else if (xzLine.x > m_shadow1Vec2.x)

{

offsetPos = vec3(place.x - m_gradPos2.x,place.y - m_gradPos2.y,place.z - m_gradPos2.z);

xzLine = normalize(offsetPos.xz);

yzLine = normalize(offsetPos.yz);

if (xzLine.x > m_shadow1Vec1.x && xzLine.x < m_shadow1Vec2.x + soften)

{

{

blue = ((soften + m_shadow1Vec2.x) - xzLine.x )/soften;

if (blue > 1.0f)

blue = 1.0f;

}

}

}

else

blue = 1.0f;

return blue;

}

float generateShadows(vec3 place, vec3 m_lightPos, vec3 m_gradPos1, vec3 m_gradPos2,

vec2 m_shadow1Vec1, vec2 m_shadow1Vec2, float m_maxHeight, float complex, float soften)

{

float blue = 0;

if (place.y < m_maxHeight)

{

vec3 offsetPos = vec3(place.x - m_lightPos.x,place.y - m_lightPos.y,place.z - m_lightPos.z);

vec2 xzLine = normalize(offsetPos.xz);

vec2 yzLine = normalize(offsetPos.yz);

if (complex == 2)

{

if (xzLine.x > m_shadow1Vec1.x && place.z > m_gradPos2.z - 0.01f && place.x < m_gradPos2.x + 0.01f)

{

return 1.0f;

}

}

if (yzLine.x > m_shadow1Vec1.y && yzLine.x < m_shadow1Vec2.y)

{

if (xzLine.x > m_shadow1Vec1.x && xzLine.x < m_shadow1Vec2.x)

{

{

return 1.0f;

}

}

blue = calcLateral(xzLine, yzLine, offsetPos, place, m_gradPos1, m_gradPos2, soften,

m_shadow1Vec1, m_shadow1Vec2);

}

else if (yzLine.x < m_shadow1Vec2.y + soften && yzLine.x > m_shadow1Vec1.y)

{

blue = calcLateral(xzLine, yzLine, offsetPos, place, m_gradPos1, m_gradPos2, soften,

m_shadow1Vec1, m_shadow1Vec2);

blue *= (m_shadow1Vec2.y + soften - yzLine.x)/soften;

}

}

return blue;

}

void main(){

vec2 newTexCoord;

float blue = 1.0f;

#ifdef USEVECSHADOWS

float complex = round(m_ShadowComplexity);

blue = generateShadows(place, m_lightPos, m_gradPos1, m_gradPos2, m_shadow1Vec1, m_shadow1Vec2, m_maxHeight, complex, m_ShadowSoften);

blue *= blue;

if (blue > 1.0f)

blue = 1.0f;

#endif

[/java]

Looks very promising!!

Nice work

New pictures! These are taken using a closet with two sliding doors. This is to illustrate the dynamic applications of the vector-based shadows.

I’ll probably start on multiple lights next.

@nehon said:

Looks very promising!!

Nice work

Thank you!

These are looking really impressive. What’s the limitations on them? I know you said something about rectangular shapes?

@zarch said:

These are looking really impressive. What's the limitations on them? I know you said something about rectangular shapes?

The vector shadow system can only use rectangular objects because of the coordinate system it uses. It converts cartesian coordinates to spherical coordinates and then determines whether the given pixel lies within the completely lit or darkened area or in a softening zone. This could possibly be extended to more complex objects as I overcome some of the more pressing limitations, possibly using a raytracer and a binary search algorithm for the LOD.

As this shader uses vector math and a spherical coordinate system, there are some mathematical issues which one would not find using a Cartesian-based coordinate system. I think these issues can be overcome as I read up on the relevant material, and possibly get some consultation from my professors.

One such issue is where a vector will be mirrored over to the opposite cartesian quadrant. For example, you have a shadow or aperture in quadrant 1 (+x,+y) which is also cast in quadrant 4(x,-y). I understand the math behind it and a dirty fix for this is to just cast anything not in quadrant 1 as a shadow or an aperture, depending on whether we want an aperture or a shadow rendered. Unfortunately, this fix also limits which angles we can use and hence the position of the light sources we can utilize for this shader.

Here are two pictures which illustrate the problem (I thought I had "fixed" the problem earlier but had actually just relocated the light source in the shader):

Image removed (problem solved) - click link for image

Image removed (problem solved) - click link for image

EDIT:

I just fixed the problem - apparently it involved some very trivial geometry. I should have gotten my cousin to do this for me!

Here we have multiple lights with the light on:

And off:

It’s getting late, so I’ll start on multiple shadow vectors tomorrow.

I have a new plane-based version of this shader. A still of it working with a relatively abstract surface is below:

I know it can theoretically work with more abstract surfaces - ie: using triangle-based rather than plane based algorithms. It’s just a matter of adding the code. I’ll probably keep the planar implementation for any appropriate surfaces for optimization reasons.

The low-ish framerate is due to a (to the best of my knowledge) lack of support for sequential texture buffers in JME3, though I’m sure I can either add this or optimize the code further to reduce global lookups.

Update: New image, just to show how thorough the implementation is right now. This is of the little metal frame around the door at a certain angle - no detail is too small to be captured using this shading algorithm. Certain optimizations can and (judging from the framerate) sometimes must be made to the input mesh, of course, to reduce the number of planes or trigs processed. Probably over 75% of the optimizations I could make to the input data right now would be lossless - just combining coplanar polys and such, so there’s still a lot of fat to trim.

http://imgur.com/kOO26

Sooo… badass XD