Skip to content

Commit bde5483

Browse files
committed
CustomEyeInteraction example added
1 parent 531a559 commit bde5483

6 files changed

Lines changed: 275 additions & 29 deletions

File tree

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
import nub.primitives.*;
2+
import nub.processing.*;
3+
4+
PImage texmap;
5+
float globeRadius = 400;
6+
int sDetail = 35; // Sphere detail setting
7+
float[] sphereX, sphereY, sphereZ;
8+
float sinLUT[];
9+
float cosLUT[];
10+
float SINCOS_PRECISION = 0.5f;
11+
int SINCOS_LENGTH = (int) (360 / SINCOS_PRECISION);
12+
13+
// nub stuff:
14+
Scene scene;
15+
boolean keyMode;
16+
17+
// size
18+
int w = 1240;
19+
int h = 840;
20+
float step = 5 * TWO_PI / w;
21+
22+
void settings() {
23+
size(w, h, P3D);
24+
}
25+
26+
void setup() {
27+
texmap = loadImage("world32k.jpg");
28+
initializeSphere(sDetail);
29+
scene = new Scene(this);
30+
scene.setRadius(globeRadius * 1.2f);
31+
scene.fit(1);
32+
}
33+
34+
void draw() {
35+
background(0);
36+
scene.drawAxes();
37+
//lights();
38+
fill(200);
39+
noStroke();
40+
textureMode(IMAGE);
41+
texturedSphere(globeRadius, texmap);
42+
}
43+
44+
void mouseDragged() {
45+
if (keyMode)
46+
return;
47+
if (mouseButton == LEFT)
48+
scene.mouseSpinEye();
49+
else if (mouseButton == RIGHT)
50+
scene.mouseTranslateEye();
51+
else
52+
scene.scaleEye(scene.mouseDX());
53+
}
54+
55+
void mouseWheel(MouseEvent event) {
56+
if (keyMode)
57+
scene.moveForward(event.getCount() * 20);
58+
}
59+
60+
void keyPressed(KeyEvent event) {
61+
if (key == ' ') {
62+
keyMode = !keyMode;
63+
if (keyMode) {
64+
/*
65+
//Node cachedEye = scene.eye().get();
66+
//Node eye = new Node(scene);
67+
//scene.setEye(eye);
68+
Node node = new Node();
69+
Vector t = new Vector(0, 0, 0.7f * globeRadius);
70+
float a = TWO_PI - 2;
71+
node.setPosition(t);
72+
//node.setYAxis(Vector.subtract(node.position(), scene.anchor()));
73+
//node.rotate(new Quaternion(a, 0, 0));
74+
scene.fit(node, 1);
75+
// */
76+
// /*
77+
Vector t = new Vector(0, 0, 0.7f * globeRadius);
78+
float a = TWO_PI - 2;
79+
scene.eye().setPosition(t);
80+
//We need to line up the eye up vector along the anchor and the camera position:
81+
scene.setUpVector(Vector.subtract(scene.eye().position(), scene.anchor()));
82+
//The rest is just to make the scene appear in front of us.
83+
scene.eye().rotate(new Quaternion(a, 0, 0));
84+
// */
85+
} else {
86+
scene.fit(1);
87+
scene.lookAtCenter();
88+
}
89+
}
90+
if (keyMode) {
91+
// Translate the eye along its reference Z-axis
92+
if (key == 'u')
93+
scene.eye().translate(0, 0, 10);
94+
if (key == 'd')
95+
scene.eye().translate(0, 0, -10);
96+
if (key == CODED) {
97+
switch (keyCode) {
98+
case UP:
99+
if (event.isShiftDown())
100+
// Rotate the eye around its X-axis -> move head up and down
101+
scene.eye().rotate(new Vector(1, 0, 0), -step);
102+
else
103+
// Orbit the eye around its X-axis -> translate forward-backward
104+
scene.eye().orbit(xAxis(), step);
105+
break;
106+
case DOWN:
107+
if (event.isShiftDown())
108+
// Rotate the eye around its X-axis -> move head up and down
109+
scene.eye().rotate(new Vector(1, 0, 0), step);
110+
else
111+
// Orbit the eye around its X-axis -> translate forward-backward
112+
scene.eye().orbit(xAxis(), -step);
113+
break;
114+
case LEFT:
115+
// /*
116+
if (event.isShiftDown())
117+
// Orbit the eye around its Z-axis -> look around
118+
scene.eye().orbit(zAxis(), -step);
119+
else
120+
// */
121+
// Orbit the eye around its Y-axis -> translate left-right
122+
scene.eye().orbit(yAxis(), -step);
123+
break;
124+
case RIGHT:
125+
// /*
126+
if (event.isShiftDown())
127+
// Orbit the eye around its Z-axis -> look around
128+
scene.eye().orbit(zAxis(), step);
129+
else
130+
// */
131+
// Orbit the eye around its Y-axis -> translate left-right
132+
scene.eye().orbit(yAxis(), step);
133+
break;
134+
}
135+
}
136+
}
137+
}
138+
139+
// eye().orbit(axis, angle) requires the axis to be defined in the world coordinate system:
140+
141+
Vector xAxis() {
142+
return scene.eye().worldDisplacement(new Vector(1, 0, 0));
143+
}
144+
145+
Vector yAxis() {
146+
return scene.eye().worldDisplacement(new Vector(0, 1, 0));
147+
}
148+
149+
Vector zAxis() {
150+
return scene.eye().worldDisplacement(new Vector(0, 0, 1));
151+
}
152+
153+
void initializeSphere(int res) {
154+
sinLUT = new float[SINCOS_LENGTH];
155+
cosLUT = new float[SINCOS_LENGTH];
156+
for (int i = 0; i < SINCOS_LENGTH; i++) {
157+
sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * SINCOS_PRECISION);
158+
cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * SINCOS_PRECISION);
159+
}
160+
float delta = (float) SINCOS_LENGTH / res;
161+
float[] cx = new float[res];
162+
float[] cz = new float[res];
163+
// Calc unit circle in XZ plane
164+
for (int i = 0; i < res; i++) {
165+
cx[i] = -cosLUT[(int) (i * delta) % SINCOS_LENGTH];
166+
cz[i] = sinLUT[(int) (i * delta) % SINCOS_LENGTH];
167+
}
168+
// Computing vertexlist vertexlist starts at south pole
169+
int vertCount = res * (res - 1) + 2;
170+
int currVert = 0;
171+
// Re-init arrays to store vertices
172+
sphereX = new float[vertCount];
173+
sphereY = new float[vertCount];
174+
sphereZ = new float[vertCount];
175+
float angle_step = (SINCOS_LENGTH * 0.5f) / res;
176+
float angle = angle_step;
177+
// Step along Y axis
178+
for (int i = 1; i < res; i++) {
179+
float curradius = sinLUT[(int) angle % SINCOS_LENGTH];
180+
float currY = -cosLUT[(int) angle % SINCOS_LENGTH];
181+
for (int j = 0; j < res; j++) {
182+
sphereX[currVert] = cx[j] * curradius;
183+
sphereY[currVert] = currY;
184+
sphereZ[currVert++] = cz[j] * curradius;
185+
}
186+
angle += angle_step;
187+
}
188+
sDetail = res;
189+
}
190+
191+
// Generic routine to draw textured sphere
192+
void texturedSphere(float r, PImage t) {
193+
int v1, v11, v2;
194+
r = (r + 240) * 0.33f;
195+
beginShape(TRIANGLE_STRIP);
196+
texture(t);
197+
float iu = (float) (t.width - 1) / (sDetail);
198+
float iv = (float) (t.height - 1) / (sDetail);
199+
float u = 0, v = iv;
200+
for (int i = 0; i < sDetail; i++) {
201+
vertex(0, -r, 0, u, 0);
202+
vertex(sphereX[i] * r, sphereY[i] * r, sphereZ[i] * r, u, v);
203+
u += iu;
204+
}
205+
vertex(0, -r, 0, u, 0);
206+
vertex(sphereX[0] * r, sphereY[0] * r, sphereZ[0] * r, u, v);
207+
endShape();
208+
// Middle rings
209+
int voff = 0;
210+
for (int i = 2; i < sDetail; i++) {
211+
v1 = v11 = voff;
212+
voff += sDetail;
213+
v2 = voff;
214+
u = 0;
215+
beginShape(TRIANGLE_STRIP);
216+
texture(t);
217+
for (int j = 0; j < sDetail; j++) {
218+
vertex(sphereX[v1] * r, sphereY[v1] * r, sphereZ[v1++] * r, u, v);
219+
vertex(sphereX[v2] * r, sphereY[v2] * r, sphereZ[v2++] * r, u, v + iv);
220+
u += iu;
221+
}
222+
// Close each ring
223+
v1 = v11;
224+
v2 = voff;
225+
vertex(sphereX[v1] * r, sphereY[v1] * r, sphereZ[v1] * r, u, v);
226+
vertex(sphereX[v2] * r, sphereY[v2] * r, sphereZ[v2] * r, u, v + iv);
227+
endShape();
228+
v += iv;
229+
}
230+
u = 0;
231+
// Add the northern cap
232+
beginShape(TRIANGLE_STRIP);
233+
texture(t);
234+
for (int i = 0; i < sDetail; i++) {
235+
v2 = voff + i;
236+
vertex(sphereX[v2] * r, sphereY[v2] * r, sphereZ[v2] * r, u, v);
237+
vertex(0, r, 0, u, v + iv);
238+
u += iu;
239+
}
240+
vertex(sphereX[voff] * r, sphereY[voff] * r, sphereZ[voff] * r, u, v);
241+
endShape();
242+
}
252 KB
Loading

examples/demos/CustomInteraction/CustomInteraction.pde renamed to examples/demos/CustomNodeInteraction/CustomNodeInteraction.pde

File renamed without changes.

‎src/nub/core/Graph.java‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3881,8 +3881,6 @@ public void rotateEye(float roll, float pitch, float yaw) {
38813881
pitch = 0;
38823882
System.out.println("Warning: graph is 2D. Roll and/or pitch reset");
38833883
}
3884-
//same as:
3885-
//eye().orbit(new Quaternion(node.worldDisplacement(quaternion.axis()), quaternion.angle()));
38863884
eye()._orbit(new Quaternion(isLeftHanded() ? -roll : roll, pitch, isLeftHanded() ? -yaw : yaw), anchor());
38873885
}
38883886

@@ -4045,7 +4043,7 @@ public void spinEye(int point1X, int point1Y, int point2X, int point2Y, float se
40454043
// 2D is an ad-hoc
40464044
float angle = (is2D() ? sensitivity : 2.0f) * (float) Math.asin((float) Math.sqrt(axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm()));
40474045
//same as:
4048-
//eye().orbit(new Quaternion(node.worldDisplacement(quaternion.axis()), quaternion.angle()));
4046+
//eye().orbit(new Quaternion(eye().worldDisplacement(axis), angle));
40494047
eye()._orbit(new Quaternion(axis, angle), anchor());
40504048
}
40514049

@@ -4142,7 +4140,7 @@ public void rotateCAD(float roll, float pitch, Vector upVector) {
41424140
quaternion = Quaternion.multiply(new Quaternion(eyeUp, eyeUp.y() < 0.0f ? roll : -roll), new Quaternion(new Vector(1.0f, 0.0f, 0.0f), isRightHanded() ? -pitch : pitch));
41434141
}
41444142
//same as:
4145-
//eye().orbit(new Quaternion(node.worldDisplacement(quaternion.axis()), quaternion.angle()));
4143+
//eye().orbit(new Quaternion(eye().worldDisplacement(quaternion.axis()), quaternion.angle()));
41464144
eye()._orbit(quaternion, anchor());
41474145
}
41484146
}

‎src/nub/core/Node.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@ public void rotate(float x, float y, float z, float angle) {
11121112
/**
11131113
* Rotates the node by the {@code quaternion} whose axis (see {@link Quaternion#axis()})
11141114
* passes through {@code point}. The {@code quaternion} {@link Quaternion#axis()} is
1115-
* defined in the node coordinate system, while {@code point} is defined in the world
1115+
* defined in this node coordinate system, while {@code point} is defined in the world
11161116
* coordinate system).
11171117
* <p>
11181118
* Note: if there's a {@link #constraint()} it is satisfied, i.e., to

‎testing/src/intellij/CustomEyeInteraction.java‎

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,13 @@ public class CustomEyeInteraction extends PApplet {
2323
Scene scene;
2424
boolean keyMode;
2525

26+
// size
27+
int w = 1240;
28+
int h = 840;
29+
float step = 5 * TWO_PI / w;
30+
2631
public void settings() {
27-
size(1240, 840, P3D);
32+
size(w, h, P3D);
2833
}
2934

3035
public void setup() {
@@ -45,19 +50,17 @@ public void draw() {
4550
texturedSphere(globeRadius, texmap);
4651
}
4752

48-
float computeAngle(float dx) {
49-
return dx * (float) Math.PI / scene.width();
50-
}
53+
// eye().orbit(axis, angle) requires the axis to be defined in the world coordinate system:
5154

52-
Vector worldXAxis() {
55+
Vector xAxis() {
5356
return scene.eye().worldDisplacement(new Vector(1, 0, 0));
5457
}
5558

56-
Vector worldYAxis() {
59+
Vector yAxis() {
5760
return scene.eye().worldDisplacement(new Vector(0, 1, 0));
5861
}
5962

60-
Vector worldZAxis() {
63+
Vector zAxis() {
6164
return scene.eye().worldDisplacement(new Vector(0, 0, 1));
6265
}
6366

@@ -99,13 +102,12 @@ public void keyPressed(KeyEvent event) {
99102
scene.eye().setPosition(t);
100103
//We need to line up the eye up vector along the anchor and the camera position:
101104
scene.setUpVector(Vector.subtract(scene.eye().position(), scene.anchor()));
102-
//The rest is just to make the scene appear in front of us. We could have just used
103-
//the space navigator itself to make that happen too.
105+
//The rest is just to make the scene appear in front of us.
104106
scene.eye().rotate(new Quaternion(a, 0, 0));
105107
// */
106108
} else {
107-
scene.lookAtCenter();
108109
scene.fit(1);
110+
scene.lookAtCenter();
109111
}
110112
}
111113
if (keyMode) {
@@ -119,34 +121,38 @@ public void keyPressed(KeyEvent event) {
119121
case UP:
120122
if (event.isShiftDown())
121123
// Rotate the eye around its X-axis -> move head up and down
122-
scene.eye().rotate(new Vector(1, 0, 0), computeAngle(-20));
124+
scene.eye().rotate(new Vector(1, 0, 0), -step);
123125
else
124-
// Orbit the eye around the world origin along the world X-axis -> translate forward-backward
125-
scene.eye().orbit(new Quaternion(worldXAxis(), computeAngle(20)));
126+
// Orbit the eye around its X-axis -> translate forward-backward
127+
scene.eye().orbit(xAxis(), step);
126128
break;
127129
case DOWN:
128130
if (event.isShiftDown())
129131
// Rotate the eye around its X-axis -> move head up and down
130-
scene.eye().rotate(new Vector(1, 0, 0), computeAngle(20));
132+
scene.eye().rotate(new Vector(1, 0, 0), step);
131133
else
132-
// Orbit the eye around the world origin along the world X-axis -> translate forward-backward
133-
scene.eye().orbit(new Quaternion(worldXAxis(), computeAngle(-20)));
134+
// Orbit the eye around its X-axis -> translate forward-backward
135+
scene.eye().orbit(xAxis(), -step);
134136
break;
135137
case LEFT:
138+
// /*
136139
if (event.isShiftDown())
137-
// Orbit the eye around the world origin along the world Z-axis -> look around
138-
scene.eye().orbit(new Quaternion(worldZAxis(), computeAngle(-20)));
140+
// Orbit the eye around its Z-axis -> look around
141+
scene.eye().orbit(zAxis(), -step);
139142
else
140-
// Orbit the eye around the world origin along the world Y-axis -> translate left-right
141-
scene.eye().orbit(new Quaternion(worldYAxis(), computeAngle(-10)));
143+
// */
144+
// Orbit the eye around its Y-axis -> translate left-right
145+
scene.eye().orbit(yAxis(), -step);
142146
break;
143147
case RIGHT:
148+
// /*
144149
if (event.isShiftDown())
145-
// Orbit the eye around the world origin along the world Z-axis -> look around
146-
scene.eye().orbit(new Quaternion(worldZAxis(), computeAngle(20)));
150+
// Orbit the eye around its Z-axis -> look around
151+
scene.eye().orbit(zAxis(), step);
147152
else
148-
// Orbit the eye around the world origin along the world Y-axis -> translate left-right
149-
scene.eye().orbit(new Quaternion(worldYAxis(), computeAngle(10)));
153+
// */
154+
// Orbit the eye around its Y-axis -> translate left-right
155+
scene.eye().orbit(yAxis(), step);
150156
break;
151157
}
152158
}

0 commit comments

Comments
 (0)