http://www.realityflux.com/abba/shadow_volumes.jpg
Source coming soon
http://www.realityflux.com/abba/fix_it_plz.jpg
Can someone help me getting rid of what I shall point out as “low_poygon_selfshading_model_syndrome”?
Btw this is the class I use to cast em shadows
import net.java.games.jogl.GL;
import java.io.IOException;
public class model_3D
{
load_model loader;
jcd_math.point3f vertices[],
color;
jcd_math.vec3f normals[],
location,
light;
face faces[];
edge edges[];
int display_list_silhouette,
display_list_model,
edge_count;
GL gl;
model_3D(load_model loader, GL gl, jcd_math.point3f color,
String model, jcd_math.vec3f light,jcd_math.vec3f location){
this.location = location;
this.loader = loader;
this.light = new jcd_math.vec3f(light);
this.color = new jcd_math.point3f(color);
this.gl = gl;
relative_light_position();
load_model(model);
}
void relative_light_position(){
light.sub(location);
}
void load_model(String model){
try{
loader.load_file(model, this);
}
catch(IOException e){}
create_displayable_model();
edge_count = construct_edges();
}
void draw_model(){
gl.glPushMatrix();
gl.glTranslatef(location.x,location.y,location.z);
gl.glColor3f(color.x,color.y,color.z);
gl.glCallList(display_list_model);
gl.glEndList();
gl.glPopMatrix();
}
void create_displayable_model(){
gl.glNewList((display_list_model=gl.glGenLists(1)),gl.GL_COMPILE);
gl.glBegin(gl.GL_TRIANGLES);
for(int i =0; i< faces.length; i++){
gl_vertex_normal(i, 2);
gl_vertex_normal(i, 1);
gl_vertex_normal(i, 0);
}
gl.glEnd();
gl.glEndList();
for(int i =0; i<faces.length; i++)
if(light.Dot(faces[i].normal) + faces[i].D>0)
faces[i].visible = true;
else
faces[i].visible = false;
}
void gl_vertex_normal(int face_index, int index){
gl.glNormal3f(normals[faces[face_index].indices[index]].x,
normals[faces[face_index].indices[index]].y,
normals[faces[face_index].indices[index]].z);
set_vertex(vertices[faces[face_index].indices[index]]);
}
void set_vertex(jcd_math.point3f p){
gl.glVertex3f(p.x,p.y,p.z);
}
int construct_edges(){
int edge_progress = 0,
edge_count = 0;
edges = new edge[faces.length*3];
for(int a = 0; a < faces.length; a++){
int i1 = faces[a].indices[0],
i2 = faces[a].indices[1],
i3 = faces[a].indices[2];
if(i1 < i2){
edges[edge_progress] = new edge();
edges[edge_progress].indices[0] = i1;
edges[edge_progress].indices[1] = i2;
edges[edge_progress].parents[0] = a;
edges[edge_progress].parents[1] = -1;
edge_count++;
edge_progress++;
}
if(i2 < i3){
edges[edge_progress] = new edge();
edges[edge_progress].indices[0] = i2;
edges[edge_progress].indices[1] = i3;
edges[edge_progress].parents[0] = a;
edges[edge_progress].parents[1] = -1;
edge_count++;
edge_progress++;
}
if(i3 < i1){
edges[edge_progress] = new edge();
edges[edge_progress].indices[0] = i3;
edges[edge_progress].indices[1] = i1;
edges[edge_progress].parents[0] = a;
edges[edge_progress].parents[1] = -1;
edge_count++;
edge_progress++;
}
}
for(int a = 0; a < faces.length; a++){
int i1 = faces[a].indices[0],
i2 = faces[a].indices[1],
i3 = faces[a].indices[2];
if(i1 > i2)
for(int b = 0; b < edge_count; b++)
if((edges[b].indices[0] == i2) &&
(edges[b].indices[1] == i1) &&
(edges[b].parents[1] == -1)){
edges[b].parents[1] = a;
break;
}
if(i2 > i3)
for(int b = 0; b < edge_count; b++)
if((edges[b].indices[0] == i3) &&
(edges[b].indices[1] == i2) &&
(edges[b].parents[1] == -1)){
edges[b].parents[1] = a;
break;
}
if(i3> i1)
for(int b = 0; b < edge_count; b++)
if((edges[b].indices[0] == i1) &&
(edges[b].indices[1] == i3) &&
(edges[b].parents[1] == -1)){
edges[b].parents[1] = a;
break;
}
}
return edge_count;
}
void cast_shadow(){
for(int i =0; i<edge_count; i++)
edges[i].reset();
gl.glDisable(gl.GL_LIGHTING);
gl.glDepthMask(false);
gl.glDepthFunc(gl.GL_LEQUAL);
gl.glEnable(gl.GL_STENCIL_TEST);
gl.glColorMask(false,false,false,false);
gl.glStencilFunc(gl.GL_ALWAYS, 1,~0);
gl.glFrontFace(gl.GL_CCW);
gl.glStencilOp(gl.GL_KEEP,gl.GL_KEEP,gl.GL_INCR);
draw_shadow();
gl.glFrontFace(gl.GL_CW);
gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_DECR);
draw_shadow();
gl.glFrontFace(gl.GL_CCW);
gl.glColorMask(true,true,true,true);
gl.glColor4f(0.1f, 0.1f, 0.1f, .4f);
gl.glEnable(gl.GL_BLEND);
gl.glBlendFunc(gl.GL_SRC_ALPHA,gl.GL_ONE_MINUS_SRC_ALPHA);
gl.glStencilFunc(gl.GL_NOTEQUAL, 0,~0);
gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_KEEP);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glBegin(gl.GL_TRIANGLE_STRIP);
gl.glVertex3f(-100f, 100f,-100f);
gl.glVertex3f(-100f,-100f,-100f);
gl.glVertex3f( 100f, 100f,-100f);
gl.glVertex3f( 100f,-100f,-100f);
gl.glEnd();
gl.glPopMatrix();
gl.glDisable(gl.GL_BLEND);
gl.glDepthFunc(gl.GL_LEQUAL);
gl.glDepthMask(true);
gl.glEnable(gl.GL_LIGHTING);
gl.glDisable(gl.GL_STENCIL_TEST);
gl.glShadeModel(gl.GL_SMOOTH);
}
void draw_shadow(){
int p1, p2,
a, b;
jcd_math.point3f v1 = new jcd_math.point3f(),
v2 = new jcd_math.point3f();
gl.glPushMatrix();
gl.glTranslatef(location.x,location.y,location.z);
for(int i=0; i<edge_count;i++)
if((faces[edges[i].parents[0]].visible &&!faces[edges[i].parents[1]].visible)||
(!faces[edges[i].parents[0]].visible) && (faces[edges[i].parents[1]].visible)){
if(!faces[edges[i].parents[0]].visible){
p1 = edges[i].indices[0];
p2 = edges[i].indices[1];
a = 0;
b = 1;
}
else{
p1 = edges[i].indices[1];
p2 = edges[i].indices[0];
a = 1;
b = 0;
}
if(!edges[i].projected[a]){
v1 = new jcd_math.point3f(vertices[p1]);
v1.sub(light);
v1.scale(200);
edges[i].projection[a] = new jcd_math.point3f(v1);
}
else
v1.set(edges[i].projection[a]);
if(!edges[i].projected[b]){
v2 = new jcd_math.point3f(vertices[p2]);
v2.sub(light);
v2.scale(200);
}
else
v2.set(edges[i].projection[b]);
gl.glBegin(gl.GL_TRIANGLE_STRIP);
set_vertex(vertices[p1]);
set_vertex(v1);
set_vertex(vertices[p2]);
set_vertex(v2);
gl.glEnd();
}
gl.glPopMatrix();
}
public static class edge{
int indices[] = new int[2],
parents[] = new int[2];
boolean draw,
projected[] = new boolean[2];
jcd_math.point3f projection[] = new jcd_math.point3f[2];
public edge(){
}
void reset(){
projected[0] = false;
projected[1] = false;
}
}
public static class face{
int indices[] = new int[3];
edge edges[] = new edge[3];
float D,
length;
jcd_math.vec3f normal = new jcd_math.vec3f();
boolean visible;
public face(int a, int b, int c,jcd_math.point3f p,jcd_math.vec3f normal){
indices[0] = a;
indices[1] = b;
indices[2] = c;
this.normal = new jcd_math.vec3f(normal);
length = normal.length();
D = -normal.Dot(new jcd_math.vec3f(p.x,p.y,p.z));
}
}
}
not sure- same thing happens in Xith3d. can anyone shed some light on this matter?
http://www.topresultmate.com/jogl/donuts.jpg
tops…
I have noticed some very strange shadow effects using Xith3d. I am assuming they will get better as the program develops and matures.
Will.
me 2 its all getting very cool in the world of java. i am making (not port) a little game using all the cool stuff.
and far as i can tell theres only little things to sort - and maybe add some cool new things.
i think the strange choppy shadows are from the other object having choppy polygons anyways? the back shadows in my donut are fine and smooth.
strange… but look how cool it all is
java cool dude
it’s possible that the shadow from your dinosuar is falling on the wrong side of the ball. Check your normals, you might have to renormalize them.
I’m guessing, from a quick look over the code, that you’re building a silluette of the model, then extruding that to create the shadow volume?
If thats the case, then its because you’re reducing an analog state (in/out of the shadow across the polygons) to a binary one (in/out on a polygon level). The complete solution escapes me at the moment, but the general gist of it is that you need to take the whole mesh, and bung it though a process to extrude the correct vertices - imagine cutting the sphere in half, dragging the parts away and connecting them with a long tube.
This way you can use the depth buffer on this new mesh to get a per pixel in/out value. Its usually done in a vertex shader, so try looking on nVidias site for shadow volumes done via that method.
Hope that helps.
Looking at ATI Shadow volumes demo, I came to the conclusion that what’s causing the “artifact” is nothing less than the low polygon count of the occluder.
I loaded a slightly more complex model and everything looked alright.
PS: Shadow volumes got nothing to do with normals, at least not when the vertices extrusions is done relatively to the light source.
I know 2d pics might be confusing per times as you lose the sense of depth, but the dragon is on the left side of the light whereas the sphere is on the right. So technically their respective shadows can’t be projected on each other. On the other hand you can notice the dragon’s shadow being perfectly casted on the torus
Do you have the whole demo somewhere?
Nope, but I think I might be able to post some code tonight.
The reason behind the delay is that I had to modify most of my code to make it compatible with MilkShape3D loader, meaning that any model extending .ms3d can cast a realistic shadow ^_^.
Before getting ms3d loader to work, I used to load my models after converting them from .obj to .jcd; I would use Java3D loader to convert em .obj models to something that has the following layout;
Number of vertices
Number of Triangles
Indexed vertex
Indexed Normal
…
…
…
Triangle vertices indices.
Triangle Normal
Vertices 8
Faces 12
15.0 -15.0 15.0
0.0 1.0 6.123234E-17
-15.0 -15.0 -15.0
0.0 1.0 6.123234E-17
-15.0 -15.0 15.0
0.0 1.0 6.123234E-17
15.0 -15.0 -15.0
0.0 1.0 6.123234E-17
15.0 15.0 -15.0
-1.0 0.0 0.0
15.0 15.0 15.0
-1.0 0.0 0.0
-15.0 15.0 -15.0
0.0 -6.123234E-17 1.0
-15.0 15.0 15.0
1.0 0.0 0.0
2 1 0
0.0 1.0 6.123234262925839E-17
1 3 0
0.0 1.0 6.123234262925839E-17
5 0 4
-1.0 0.0 0.0
0 3 4
-1.0 0.0 0.0
3 1 4
0.0 -6.123234262925839E-17 1.0
1 6 4
0.0 -6.123234262925839E-17 1.0
7 6 2
1.0 0.0 0.0
6 1 2
1.0 0.0 0.0
5 4 7
0.0 -1.0 -6.123234262925839E-17
4 6 7
0.0 -1.0 -6.123234262925839E-17
2 0 7
0.0 6.123234262925839E-17 -1.0
0 5 7
0.0 6.123234262925839E-17 -1.0
^ that’s a box in jcd format
I’m still working on per pixel lighting as well as phong shading, vertex shaders imlpementation, but hey I can call the code Alpha tonight and put it on somewhere ;D
http://www.realityflux.com/abba/Shadows.zip
Lots of bugs, poorly written functions, not optimized etc…
I feel tired and I have to be up at 5 am to go to New Hampshire with my buddies.
Will try to tweak it up within the next few days :-/
The demo now works with any ms3d models, grab it from here
In your demo_main-class you have a print_fps()-method which looks kind of strange:
if(System.currentTimeMillis() - start >=500){
fps = count_fps<<1;
start = 0;
count_fps = 0;
}
It should be System.currentTimeMillis() - start >=1000 or fps = 2*count_fps. Right?
BTW, this way you can double your framerate. 8)
Besides this I get some exceptions and a blank gray screen when starting your demo on Linux.
Exception in thread "main" java.lang.NullPointerException
at demo_main.main(demo_main.java:85)
java.lang.NullPointerException
at TextureManager.bindTexture(TextureManager.java:31)
at make_room.make_room(make_room.java:33)
at make_room.<init>(make_room.java:17)
at demo_main.initialize(demo_main.java:163)
at init_renderer.init(init_renderer.java:50)
at net.java.games.jogl.impl.GLDrawableHelper.init(GLDrawableHelper.java:68)
at net.java.games.jogl.GLCanvas$InitAction.run(GLCanvas.java:201)
at net.java.games.jogl.impl.x11.X11GLContext.makeCurrent(X11GLContext.java:146)
at net.java.games.jogl.impl.x11.X11OnscreenGLContext.makeCurrent(X11OnscreenGLContext.java:111)
at net.java.games.jogl.impl.GLContext.invokeGL(GLContext.java:162)
at net.java.games.jogl.GLCanvas.displayImpl(GLCanvas.java:196)
at net.java.games.jogl.GLCanvas.display(GLCanvas.java:91)
at net.java.games.jogl.GLCanvas.paint(GLCanvas.java:102)
at sun.awt.RepaintArea.paint(RepaintArea.java:177)
at sun.awt.motif.MComponentPeer.handleEvent(MComponentPeer.java:374)
at java.awt.Component.dispatchEventImpl(Component.java:3658)
at java.awt.Component.dispatchEvent(Component.java:3439)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:450)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)
java.lang.NullPointerException
at demo_main.keyPressed(demo_main.java:203)
at java.awt.Component.processKeyEvent(Component.java:5051)
at java.awt.Component.processEvent(Component.java:4902)
at java.awt.Component.dispatchEventImpl(Component.java:3598)
at java.awt.Component.dispatchEvent(Component.java:3439)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1688)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:593)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:765)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:698)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:559)
at java.awt.Component.dispatchEventImpl(Component.java:3468)
at java.awt.Component.dispatchEvent(Component.java:3439)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:450)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)
net.java.games.jogl.GLException: Error making context current
at net.java.games.jogl.impl.x11.X11GLContext.makeCurrent(X11GLContext.java:141)
at net.java.games.jogl.impl.x11.X11OnscreenGLContext.makeCurrent(X11OnscreenGLContext.java:111)
at net.java.games.jogl.impl.GLContext.invokeGL(GLContext.java:162)
at net.java.games.jogl.GLCanvas.displayImpl(GLCanvas.java:196)
at net.java.games.jogl.GLCanvas.display(GLCanvas.java:91)
at net.java.games.jogl.GLCanvas.paint(GLCanvas.java:102)
at sun.awt.RepaintArea.paint(RepaintArea.java:177)
at sun.awt.motif.MComponentPeer.handleEvent(MComponentPeer.java:374)
at java.awt.Component.dispatchEventImpl(Component.java:3658)
at java.awt.Component.dispatchEvent(Component.java:3439)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:450)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)
I can’t comment on your exceptions or frame-rate halving issue, but that “count_fps<<1” actually is a “count_fps * 2”! ;D
Deciding that multiplication isn’t cool enough for him, Java Cool Dude has resorted to a binary shift by one, promoting all binary bits in the number to double their original values. A neat trick, which gets disapproving sighs from the Correctness people, but extra Style Points from the rest of us… 8) :
** Disapproving Sigh **
Readability
Kev
Oops, I should have noticed that. :
Java Cool Dude seems to have an extraordinary coding style anyway.
[quote]For instance in the demo I’m showing right here, when I call the function named cast_shadow() it’s straight obvious that what it does is actually casting a shadow.
[/quote]
well, yes, but I guess that the “complaint” wasn’t against your name per se - but the way it “looks”. The java standard is to have
cast_shadow() named as castShadow()
This is only a recommendation and you can of course use whatever you want
hahhahaha u think hes bad!
Just so that your thread isn’t contaminated with my posts, I’ve deleted them. It was obviously a waste of time giving you any form of feedback.
Frankly, I think your code speaks for itself.
Kev
That’s much much better.
I honestly don’t give a flying poop about your opinion as you obviously lack the skills and the manners to clearly state it.
Now regarding this last comment
Frankly, I think your code speaks for itself.
it definitely shows your true colors :
I’ll keep my code and you’ll keep your mindless babbling for now mmmmmmk? ;D