The following code puts a cube at (0, 0, 0) and another at (0, .5, .5) and each cube is (.5, .5, .5) in dimension. I'm trying to rotate the view that the screen gets to one like this but instead I get this view . Also, I realize I got the colors backwards.
Anyway, this is my code so far:
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class Positioning {
private Color3f lightBlue;
private Color3f aquaGreen;
private Color3f white;
private Color3f teal;
private BranchGroup group;
private SimpleUniverse universe;
public Positioning() {
lightBlue = new Color3f(0.0f, 0.749019608f, 1.0f);
aquaGreen = new Color3f(0.439215686f, 0.858823529f, 0.576470588f);
white = new Color3f(1.0f, 1.0f, 1.0f);
teal = new Color3f(0.196078431f, 0.6f, 0.8f);
universe = new SimpleUniverse();
group = new BranchGroup();
addCube(0.5f, 0.5f, 0.5f, new Vector3f(0.0f, 0.0f, 0.0f), lightBlue);
addCube(0.5f, 0.5f, 0.5f, new Vector3f(0.5f, 0.0f, 0.5f), aquaGreen);
//add light
DirectionalLight light1 = new DirectionalLight(white, new Vector3f(0.0f, 7.0f, -12.0f));
light1.setInfluencingBounds(new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0));
group.addChild(light1);
//look at the right spot
Transform3D lookAt = new Transform3D();
lookAt.lookAt(new Point3d(0.0, 0.0, 3.0), new Point3d(0.0, 0.0, 0.0), new Vector3d(1.0, 1.0, 0.0));
lookAt.invert();
universe.getViewingPlatform().getViewPlatformTransform().setTransform(lookAt);
universe.addBranchGraph(group);
}
public void addCube(float x, float y, float z, Vector3f position, Color3f color) {
TransformGroup tg = new TransformGroup();
Transform3D trans = new Transform3D();
Appearance app = new Appearance();
Material mat = new Material();
mat.setDiffuseColor(color);
mat.setSpecularColor(color);
app.setMaterial(mat);
Box b = new Box(x, y, z, app);
//move into position and add to the branch group
trans.setTranslation(position);
tg.setTransform(trans);
tg.addChild(b);
group.addChild(tg);
}
public static void main(String[] args) {
new Positioning();
}
}
So right now the canvas is black and I think it might be my positioning on the lookAt function. I'm also not exactly for sure what the up vector is for. Any ideas on how to fix this?
I'm not familiar with Java but usually you can set up a view matrix using some sort of "lookAt" function. A quick look at the docs came up with this.
BTW, setNominalViewingTransform only translates along the z-axis so the screenshot you showed is what I would expect to see. You are correct to try to set the view transform yourself.
Edit
As far as the up direction for the lookAt function is concerned this is just a way of controlling the roll of the camera. In other words by specifying the eye point and the centre point (the point the camera is looking at) you have only defined a direction. The camera could still rotate 360 degrees on that axis. If you want to look at things the right way up then just specify a vector in the direction of "up" in your system - if that is y then it would be (0,1,0). If you wanted to look at things upside down then it would be (0,-1,0).
Note that you don't have to make sure that the "up" vector is perpendicular to the direction defined by eye and centre. As long as it's not parallel to that direction then the method should automatically just use the component of your supplied "up" vector that is perpendicular to the direction.
Edit2:
Based on your edits it looks as if you have put in a position for the "up" vector rather than a direction. It should just be the vector (0,1,0). Having said that it still won't fix your problem as an incorrect "up" vector just means that the camera might end up rolled around on its own axis so that it's upside-down, on its side, etc., but it won't affect the direction.
Therefore there must be something wrong with the eye and centre positions or the matrix is still not inverted. Your edit for the invert() looks wrong as you haven't called it on your lookAt Transform3D but I assume that's just a typo. when you updated the question?
I would try a simpler viewing angle to start with. Just try to look along the z-axis with something like
Transform3D lookAt = new Transform3D();
lookAt.lookAt( new Point3d( 0.0, 0.0, 1.0 )
, new Point3d( 0.0, 0.0, 0.0 )
, new Vector3d( 0.0, 1.0, 0.0) );
lookAt.invert();
What happens with that?
If you still get black then try changing the eye point's position along the z-axis, perhaps try 2.0, 3.0 and then a few negative values too.
The other possibility is that your camera is looking in the right direction but the objects are being culled due to frustum clipping. You might want to check the documentation to see what the default clip planes are set to. This might show up in the example above when you change the eye position along the z-axis. If you can see your objects for some values of z but not others then it's probably a clipping problem.
Let me know how you get on.
Related
I have an application, where all scene objects are loaded from .obj files (they are exported from Blender). And I need to rotate one of this objects around specific point. Currently, I have the following code:
public void rotateTo() {
// translate to origin, rotate, translate back
Vector3f origin = new Vector3f();
Vector3f pivot = new Vector3f(.0f, .5f, .0f);
this.getTransform(this.transform);
this.transform.get(origin);
double angle = -Math.PI / 2;
double newX = origin.getX() + Math.cos(angle) * (pivot.getX() - origin.getX()) - Math.sin(angle) * (pivot.getY() - origin.getY());
double newY = origin.getY() + Math.sin(angle) * (pivot.getX() - origin.getX()) + Math.cos(angle) * (pivot.getY() - origin.getY());
this.transform.set(new Vector3f((float)newX, (float)newY, .0f), 0.15f);
this.setTransform(this.transform);
this.transform.set(origin, 0.15f);
this.setTransform(this.transform);
}
Where this refers to TransformGroup object, that I need to rotate, and this.transform refers to Transform3D object.
But this method doesn't work as I expected. I have also tried this and this solutions, but they also didn't work for me.
I think, maybe, try to perform this manipulation with the help of GeometryArray, but I can't understand, how to do this. Also, I can try to export my objects with different origin points, but it's not clean solution, I think, because then I would need to move them to right positions with code.
Here's my object:
I'm trying to rotate it around green point, but in all cases it rotates around red point, or doesn't rotate at all, or translates to some point without rotation.
P.S. I know, that Java3D is an old library and can use more powerful tools, but it's my university professor's requirement and I can't refuse using it.
Composition of transformations can be achieved using matrix multiplication. Below is an example that rotates a cube 180° about the X axis with the pivot at the centre of its top face.
There are three steps as mentioned in the question: translate so that the pivot is at the origin, rotate, and translate back. Comment out steps to see what is happening.
With all steps commented out, the box appears at the centre with its red side facing forward.
Uncomment the first step. The box shifts down so its top is at the centre of the screen.
Uncomment the second step. The box rotates about the X axis (the left-right axis, through the top of the box). The green side now faces forward, and the bottom of the box is now at the centre of the screen.
Uncomment the third step. The box shifts up, and the overall effect is that it rotated about a left-right axis through its top face.
The application of a transformation T to a vector v is defined as T*v in Java 3D, so the composition of two transformations T and U where T is to be done first and U is to be done second is U*T. Note how the order is reversed. In general, the composition of the transformations T1, T2, ..., Tn where T1 is done first and Tn is done last is Tn*...*T2*T1.
This can be expressed in Java 3D using the following pattern:
Transform3D t1 = ..., t2 = ..., t3 = ...;
// first do t1, then t2, then t3
Transform3D all = new Transform3D(); // all = identity
all.mul(t1, all); // all = t1 * all
all.mul(t2, all); // all = t2 * all
all.mul(t3, all); // all = t3 * all
// now all == t3 * t2 * t1
Methods such as Transform3D.set(Vector3d,double) and TransformGroup.setTransform() overwrite the existing transformation rather than compose with it, which is one of the reasons your code does not work.
I found the article http://www.developer.com/java/other/article.php/3717101/Understanding-Transforms-in-Java-3D.htm helpful.
// based on http://www.java3d.org/starting.html
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
import javax.media.j3d.*;
import javax.vecmath.*;
public class Demo
{
public Demo() {
SimpleUniverse universe = new SimpleUniverse();
BranchGroup group = new BranchGroup();
group.addChild(createModel());
universe.getViewingPlatform().setNominalViewingTransform();
universe.addBranchGraph(group);
}
Node createModel() {
double radius = 0.3;
ColorCube cube = new ColorCube(radius);
// rotation of cube about the center of the top face
// i.e. the point (x=0, y=radius, z=0)
Transform3D transform = new Transform3D();
// step 1: translate cube down so that (0, radius, 0) is at the origin
Transform3D translate1 = new Transform3D();
translate1.setTranslation(new Vector3d(0.0, -radius, 0.0));
transform.mul(translate1, transform);
// step 2: rotate cube about X axis by 180 degrees
Transform3D rotate = new Transform3D();
rotate.rotX(Math.PI);
transform.mul(rotate, transform);
// step 3: translate cube back up
Transform3D translate2 = new Transform3D();
translate2.setTranslation(new Vector3d(0.0, +radius, 0.0));
transform.mul(translate2, transform);
// create a TransformGroup
TransformGroup tg = new TransformGroup();
tg.setTransform(transform);
tg.addChild(cube);
return tg;
}
public static void main(String[] args) {
new Demo();
}
}
I have a very simple Java3D application, it contains two cubes, of which one of them orbits the other.
Like so:
As you can see, the default position for the viewing platform is from a 'kind of' birds eye view.
The code that looks like so
TransformGroup cameraTG = u.getViewingPlatform().
getViewPlatformTransform();
Vector3f translate = new Vector3f();
Transform3D T3D = new Transform3D();
translate.set( 0.0f, 0.0f, 20.0f);
T3D.setTranslation(translate);
cameraTG.setTransform(T3D);
My question is, is it possible to set the viewing platform to track the larger cube (the cube that rotates around the smaller square). Or more straight forward, is it possible for the viewing platform to rotate around a given body?
More information:
My goal is to have a miniature solar system, containing the Sun, Earth and moon. And I would like to view it from the point of view of the earth (almost like a view from the ISS)
Any help or pointers would be fantastic. Please feel free to ask for more information if needed.
You have a nice example here http://java3d.nl/Tutorials/Java/Java3d/Controlthecamera_12.php
The original http://java3d.nl website is no longer available, but you can still use the cached version from the Internet Archive: https://web.archive.org/web/20131218022035/http://java3d.nl/Tutorials/Java/Java3d/Controlthecamera_12.php
this.camera = this.universe.getViewingPlatform().getViewPlatformTransform();
//Add things to the universe
this.root = new BranchGroup();
this.root.addChild(new ColorCube(0.2));
this.universe.addBranchGraph(root);
My idea is like this:
BranchGroup b=new BranchGroup();
b.addChild(cube);
b.addChild(camera);
then in a loop where you rotate the block:
while(true) {
... b.getChild()......... etc
apply transform
}
or more specifically
for(j=0; j<group.numChildren(); j++) {
Node ni=group.getChild(j);
if(ni instanceof TransformGroup) {
Transform3D tdi=new Transform3D();
TransformGroup tgi=(TransformGroup)group.getChild(j);
tgi.getTransform(tdi);
Transform3D rotation = new Transform3D();
rotation.rotX(Math.toRadians(0.001*i));
tdi.mul(rotation);
tgi.setTransform(tdi);
}
}
There is a simpler solution. Instaed of trying to control the viewer gaze using angles and rotation, you can merely say what 3D point to look at. In the ViewingTransform, you can call "lookAt(...)":
TransformGroup viewingTransformGroup = simpleUniv.getViewingPlatform().getViewPlatformTransform();
Transform3D viewingTransform = new Transform3D();
Point3d eye = viewersLocation;
Point3d center = gazePoint;
Vector3d up = new Vector3d(0,1,0); //assumes +y-axis points up
viewingTransform.lookAt(eye, center, up);
viewingTransform.invert();
viewingTransformGroup.setTransform(viewingTransform);
The question change a bit, I figured out how to rotate around a single axis
I want to rotate a box around the Y axis using an angle.
The box has a size, and a Vector3f to signal the rotation.
To rotate the box correctly what I do is rotate the origin position then rotate the origin position plus the size, and use those two references to render the box.
However this rotation does not work correctly and causes rendering artifacts.
This is my code to rotate the positions:
Matrix4f matrix = new Matrix4f();
// Rotate the origin position
Vector3f pos = new Vector3f(new Vector3f(blockX, blockY, blockZ));
matrix.m03 = pos.x;
matrix.m13 = pos.y;
matrix.m23 = pos.z;
Vector3f rot = new Vector3f(new Vector3f(0, 1f, 0f));
Matrix4f.rotate((float) Math.toRadians(45f), rot, matrix, matrix);
Vector3f locationMin = new Vector3f(matrix.m03, matrix.m13, matrix.m23);
// Rotate the position with the size
// Top left back is the position of the block
Vector3f sizeRot = new Vector3f(new Vector3f(blockX + size, blockY + size, blockZ + size));
matrix = new Matrix4f();
matrix.m03 = sizeRot.x;
matrix.m13 = sizeRot.y;
matrix.m23 = sizeRot.z;
rot = new Vector3f(new Vector3f(0, 1f, 0f));
Matrix4f.rotate((float) Math.toRadians(45f), rot, matrix, matrix);
Vector3f locationMax = new Vector3f(matrix.m03, matrix.m13, matrix.m23);
// Then here I use the locationMax and the locationMin to render the cube
What could be wrong with this code? Is the logic I am using to rotate the box correct? as in rotate the origin position then rotate the origin position plus the size..
EDIT: I released that rotating after translating is stupid so instead I just rotated the locationMax which is not translated (it is only the size) then I translated and I still get the same result (Graphical Artifacts).
New Code:
float rx = blockX, ry = blockY, rz = blockZ;
Matrix4f matrix = new Matrix4f();
Vector3f rot = new Vector3f(0, 1f, 0f);
matrix = new Matrix4f();
matrix.m03 = size;
matrix.m13 = size;
matrix.m23 = size;
Matrix4f.rotate((float) Math.toRadians(45f), rot, matrix, matrix);
matrix.translate(new Vector3f(rx, ry, rz), matrix);
float mx = matrix.m03;
float my = matrix.m13;
float mz = matrix.m23;
// Here is use rx, ry, rz and mx, my, mz to render the box
============ * I figured it out (See below)* =============
EDIT:
This is what I ended up doing:
// Origin point
Vector4f a = new Vector4f(blockX, blockY, blockZ, 1);
// Rotate a matrix 45 degrees
Matrix4f mat = new Matrix4f();
mat.rotate((float) Math.toRandians(45f), new Vector3f(
0, 1f, 0), mat);
/* Transform the matrix to each point */
Vector4f c = new Vector4f(size.x, 0, size.z, 1);
Matrix4f.transform(mat, c, c);
Vector4f.add(c, a, c);
Vector4f b = new Vector4f(size.x, 0, 0, 1);
Matrix4f.transform(mat, b, b);
Vector4f.add(b, a, b);
Vector4f d = new Vector4f(0, 0, size.z, 1);
Matrix4f.transform(mat, d, d);
Vector4f.add(d, a, d);
// Here is use a, b, c, and d to render the box.
The problem with this is that I want to rotate around all axises and not only around the Y axis. This makes the code very long and unreadable and There are a lot of bugs when I try to rotate around all axises.
Update Question:
How do I take the above code and make it so I can rotate around all 3 axises. I want to do this so I can have a billboard that will always face the camera.
This is how I calculate the angle between the camera and the object:
Vector3f angle = new Vector3f();
// Calculate the distance between camera and object
Vector3f.sub(game.getCamera().getLocation(),
new Vector3f(blockX, blockY, blockZ), angle);
// Calculate the angle around the Y axis.
float vectorAngle = (float) ((float) Math.atan2(angle.z, angle.x) * -1 + (Math.PI / 2.0f));
Billboards are a very common application of computer graphics (as I'm sure you've noticed, since you're asking the question!)
Ultimately I think you are over complicating the problem, based on:
as in rotate the origin position then rotate the origin position plus the size..
For computer graphics, the most common transformations are Scaling, Translating, and Rotating, and you do these in an order to achieve a desired effect (traditionally you scale, then rotate about the origin, then translate the vertex's position).
Additionally, you will have three main matrices to render a model in 3d: World Matrix, View Matrix, and Projection Matrix. I believe you are having misunderstandings of transforming from Model Space to World Space.
Graphics TRS and Matrix info. If you are having conceptual problems, or this answer is insufficient, I highly recommend looking at this link. I have yet to find a better resource explaining the fundamentals of computer graphics.
So right at the moment, you have your three angles (in degrees, in a Vector3) corresponding to the angle difference in the X,Y, and Z coordinate spaces from your billboard and your camera. With this information, we generate the View matrix by first gathering all of our matrix transformations in one place.
I'm going to assume that you already have your Translation and Scaling matrices, and that they both work. This means that we only need to generate our Rotation matrix, and then transform that matrix with the scaling matrix, and then transforming that matrix by our translation matrix.
X Rotation Matrix
Y Rotation Matrix
Z Rotation Matrix
(Images taken from CodingLabs link above)
So you will generate these three matrices, using the X,Y, and Z angles you calculated earlier, and then transform them to consolidate them into a single matrix, transform that matrix by the scaling matrix, and then transform that matrix by the translation matrix. Now you have your awesome matrix that, when you multiply a a vertex by it, will transform that vertex into the desired size, rotation, and position.
So you transform every single vertex point by this generated matrix.
And then after that, you should be done! Using these techniques will hopefully simplify your code greatly, and set you on the right path :)
So now how about some code?
//I do not guarantee that this code compiles! I did not write it in an IDE nor did I compile it
float angleToRotX = 180f;
float angleToRotY = 90f;
float angleToRotZ = 0f;
// example vertex
Vector4f vertex = new Vector4f(0, 1, 0, 1);
// Rotate vertex's X coordinates by the desired degrees
Matrix4f rotationXMatrix = new Matrix4f();
rotationXMatrix.rotX(angleToRotX);
Matrix4f rotationYMatrix = new Matrix4f();
rotationYMatrix.rotY(angleToRotY);
Matrix4f rotationZMatrix = new Matrix4f();
rotationZMatrix.rotZ(angleToRotZ);
//now let's translate it by 1.5, 1, 1.5 in the X,Y,Z directions
Matrix4f translationMatrix = new Matrix4f();
translationMatrix.setTranslate(new Vector3f(1.5, 1, 1.5));
/*
Now we have our three rotational matrices. So we multiply them (transform them) to get a single matrix to transform all of the points in this model to the desired world coordinates
*/
Matrix4f rotationMatrix = new Matrix4f();
rotationMatrix.mul(rotationXMatrix);
rotationMatrix.mul(rotationYMatrix);
rotationMatrix.mul(rotationZMatrix);
Matrix4f worldMatrix = translationMatrix;
worldMatrix.mul(rotationMatrix);
//now worldMatrix, when applied to a vertex, will rotate it by X,Y,Z degrees about the origin of it's model space, and then translate it by the amount given in translationMatrix
worldMatrix.transform(vertex);
//now vertex should be (1.5, 0, 1.5, 1) with (x,y,z,1)
Now this code could really be simplified, and it is excessively verbose. Try it out! I don't have java downloaded on my machine, but I grabbed the methods from the java documentation Here
Here is an image of what is happening (again, taking from coding labs):
(Advanced Info: Quaternions. These are really cool way of orienting a model in 3d space, however I don't quite understand them to the degree I need to in order to explain it to someone else, and I also believe that your problem is more fundamental)
You could generate the matrix without much hassle. The OpenGL matrix looks like the following:
|lx,ux,vx,px| - lx,ly,lz = the left vector
|ly,uy,vy,py| - ux,uy,uz = the up vector
|lz,uz,vz,pz| - vx,vy,vz = the view vector
|0 ,0 ,0 ,1 | - px,py,pz = the translation
All you need to do, is set px,py,pz to the position of your box in the world,
your view vector to the normalized(camera position - box position), your up comes straight from your camera, and the left is calculated via normalized cross product. It's also good practice to reconstruct the up vector, after left one is derived (by another cross product). That's all there's to it.
My solution aims to save you some time coding, rather than explain everything in detail. Hope that is useful to someone.
I'm trying to get the lights and reflection correct in my program. I have a big sphere, which I can move the the mouse, that should be a light source (LIGHT0), and smaller spheres bouncing around that should reflect the light. I also need a directional light that I can change the direction using the keyboard
first some colors I defined:
float whitish[] = {0.8f, 0.8f, 0.8f, 1};
float white[] = {1, 1, 1, 1};
float blackish[] = {0.2f, 0.2f, 0.2f, 1};
float black[] = {0, 0, 0, 1}
I create the directional light with
gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, blackish,0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, white,0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, white,0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, spot_position,0);
spot_position is initially [ 0, 0, 1, 0] but it can change by pressing the keyboard keys. a key press adds 0.05 to a specific component of the position vector, until it reaches 1, then it resets back to -1 (nothing fancy).
The light of the center sphere is:
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, position,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, blackish,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, white,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, white,0);
This light's position is always centered inside my big transparent sphere. w component of the position vector is 1.
I have this code to draw the picture in the back
gl.glBegin(GL_QUADS);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, white,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, white,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, white,0);
// Back Face
gl.glNormal3f(0, 0, 1);
gl.glTexCoord2f(texRight, texBottom);
gl.glVertex3f(rx2, ry1, rz1);
gl.glTexCoord2f(texRight, texTop);
gl.glVertex3f(rx2, ry2, rz1);
gl.glTexCoord2f(texLeft, texTop);
gl.glVertex3f(rx1, ry2, rz1);
gl.glTexCoord2f(texLeft, texBottom);
gl.glVertex3f(rx1, ry1, rz1);
To draw the spheres, I use the following functions:
public void drawtriangle(float[] v1, float[] v2, float[] v3) {
gl.glBegin(GL.GL_TRIANGLES);
gl.glNormal3fv(v1, 0);
gl.glVertex3fv(v1, 0);
gl.glNormal3fv(v2, 0);
gl.glVertex3fv(v2, 0);
gl.glNormal3fv(v3, 0);
gl.glVertex3fv(v3, 0);
gl.glEnd();
}
private void subdivideSphere2(float v1[], float v2[], float v3[], long depth) {
float v12[] = new float[3];
float v23[] = new float[3];
float v31[] = new float[3];
int i;
if (depth==0) {
float[] color= {v1[0]*v1[0], v2[1]*v2[1], v3[2]*v3[2], alpha};
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, blackish,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, color,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, color,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, color,0);
drawtriangle(v1, v2, v3);
return;
}
for (i = 0; i<3; i++) {
v12[i] = v1[i]+v2[i];
v23[i] = v2[i]+v3[i];
v31[i] = v3[i]+v1[i];
}
normalize(v12);
normalize(v23);
normalize(v31);
subdivideSphere2(v1, v12, v31, depth-1);
subdivideSphere2(v2, v23, v12, depth-1);
subdivideSphere2(v3, v31, v23, depth-1);
subdivideSphere2(v12, v23, v31, depth-1);
}
public void drawSphere() {
subdivideSphere2(sVdata[0], sVdata[1], sVdata[2], depth);
subdivideSphere2(sVdata[0], sVdata[2], sVdata[4], depth);
subdivideSphere2(sVdata[0], sVdata[4], sVdata[5], depth);
subdivideSphere2(sVdata[0], sVdata[5], sVdata[1], depth);
subdivideSphere2(sVdata[3], sVdata[1], sVdata[5], depth);
subdivideSphere2(sVdata[3], sVdata[5], sVdata[4], depth);
subdivideSphere2(sVdata[3], sVdata[4], sVdata[2], depth);
subdivideSphere2(sVdata[3], sVdata[2], sVdata[1], depth);
}
My problem is, the small spheres aren't reflecting light at all. They are very bright all the time. I can see a little bit of the light being reflected in the green lines of the cube when I move the big sphere closer to them, but no effect at all to the spheres. Also, I can't see any difference when I move the directional light (LIGHT1). I don't see any reflection on the lines of the cube, the big sphere, small spheres or the picture in the back. Below is screenshot of my program. How can I make my spheres not shine, and reflect both the directional light and the light from the big sphere? Any help would be greatly appreciated. Thank you.
It looks like the lightning is disabled when tracing your small spheres. I don't see the code where you call the drawSphere but it really looks like you are tracing the Big sphere with GL_LIGHTING enabled and the small spheres with GL_LIGHTING disabled.
By reflect the light do you mean that it is illuminated? Reflection involves ray tracing and is a much bigger subject.
I don't have direct experience with JOGL but I've used jME3 a fair amount and this sort of problem there is usually caused either by using an unlit material (which doesn't seem to be the case here as you say it is being lit a bit), by bad normals on the object, or by simply having the ambient light and/or the ambient color of the material turned up too high.
As far as I can tell you are not setting the normals correctly. A normal should basically point into the direction you want to reflect the light to, which is usually "90° away" from the triangle (use the cross product). OpenGL will then use that normal to calculate the actual lighting reflected by the surface. See this tutorial for further explanation.
The other problem is that you use the outdated OpenGL 2.0 functionality, which does vertex-based lighting, so effectively each triangle in your sphere is lightened to the same value. If you are looking for per-pixel lighting, which is close to impossible using the outdated functionality unless the sphere has as many vertices as it has pixels on the screen, you need to update your code and use Shaders.
This tutorial isn't Java, but it explains the basics of modern OpenGL very well, and should be easily translatable to JOGL.
I think it can be done by applying the transformation matrix of the scenegraph to z-normal (0, 0, 1), but it doesn't work. My code goes like this:
Vector3f toScreenVector = new Vector3f(0, 0, 1);
Transform3D t3d = new Transform3D();
tg.getTransform(t3d); //tg is Transform Group of all objects in a scene
t3d.transform(toScreenVector);
Then I tried something like this too:
Point3d eyePos = new Point3d();
Point3d mousePos = new Point3d();
canvas.getCenterEyeInImagePlate(eyePos);
canvas.getPixelLocationInImagePlate(new Point2d(Main.WIDTH/2, Main.HEIGHT/2), mousePos); //Main is the class for main window.
Transform3D motion = new Transform3D();
canvas.getImagePlateToVworld(motion);
motion.transform(eyePos);
motion.transform(mousePos);
Vector3d toScreenVector = new Vector3f(eyePos);
toScreenVector.sub(mousePos);
toScreenVector.normalize();
But still this doesn't work correctly. I think there must be an easy way to create such vector. Do you know what's wrong with my code or better way to do so?
If I get this right, you want a vector that is normal to the screen plane, but in world coordinates?
In that case you want to INVERT the transformation from World -> Screen and do Screen -> World of (0,0,-1) or (0,0,1) depending on which axis the screen points down.
Since the ModelView matrix is just a rotation matrix (ignoring the homogeneous transformation part), you can simply pull this out by taking the transpose of the rotational part, or simple reading in the bottom row - as this transposes onto the Z coordinate column under transposition.
Yes, you got my question right. Sorry that I was a little bit confused yesterday. Now I have corrected the code by following your suggestion and mixing two pieces of code in the question together:
Vector3f toScreenVector = new Vector3f(0, 0, 1);
Transform3D t3d = new Transform3D();
canvas.getImagePlateToVworld(t3d);
t3d.transform(toScreenVector);
tg.getTransform(t3d); //tg is Transform Group of all objects in a scene
t3d.transform(toScreenVector);
Thank you.