Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Ability to Keep head tilt straight #48

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Panorama/PanoramaView.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
/// forward vertical altitude (-.5π to .5π)
@property (nonatomic, readonly) float lookAltitude;

// bool Keep "head" from tilting defaults to true.
@property (nonatomic) BOOL headTilt;
// Y axis stop point to reduce fluttering at extremes. Defaults to 0.9
@property (nonatomic) float yStop;

// At this point, it's still recommended to activate either OrientToDevice or TouchToPan, not both
// it's possible to have them simultaneously, but the effect is confusing and disorienting
Expand Down
117 changes: 63 additions & 54 deletions Panorama/PanoramaView.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ @interface PanoramaView (){
@implementation PanoramaView

-(id) init{
// it appears that iOS already automatically does this switch, stored in UIScreen mainscreen bounds
// CGRect frame = [[UIScreen mainScreen] bounds];
// if(SENSOR_ORIENTATION == 3 || SENSOR_ORIENTATION == 4){
// return [self initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.height, frame.size.width)];
// } else{
// return [self initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height)];
// }
// it appears that iOS already automatically does this switch, stored in UIScreen mainscreen bounds
// CGRect frame = [[UIScreen mainScreen] bounds];
// if(SENSOR_ORIENTATION == 3 || SENSOR_ORIENTATION == 4){
// return [self initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.height, frame.size.width)];
// } else{
// return [self initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height)];
// }
return [self initWithFrame:[[UIScreen mainScreen] bounds]];
}
- (id)initWithFrame:(CGRect)frame{
Expand All @@ -77,11 +77,13 @@ -(id) initWithFrame:(CGRect)frame context:(EAGLContext *)context{
[self initOpenGL:context];
sphere = [[Sphere alloc] init:48 slices:48 radius:10.0 textureFile:nil];
meridians = [[Sphere alloc] init:48 slices:48 radius:8.0 textureFile:@"equirectangular-projection-lines.png"];
_headTilt = true;
_yStop = 0.9;
}
return self;
}
-(void) didMoveToSuperview{
// this breaks MVC, but useful for setting GLKViewController's frame rate
// this breaks MVC, but useful for setting GLKViewController's frame rate
UIResponder *responder = self;
while (![responder isKindOfClass:[GLKViewController class]]) {
responder = [responder nextResponder];
Expand Down Expand Up @@ -151,9 +153,9 @@ -(void)rebuildProjectionMatrix{
}
-(void) customGL{
glMatrixMode(GL_MODELVIEW);
// glEnable(GL_CULL_FACE);
// glCullFace(GL_FRONT);
// glEnable(GL_DEPTH_TEST);
// glEnable(GL_CULL_FACE);
// glCullFace(GL_FRONT);
// glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
Expand All @@ -163,34 +165,34 @@ -(void)draw{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix(); // begin device orientation

_attitudeMatrix = GLKMatrix4Multiply([self getDeviceOrientationMatrix], _offsetMatrix);
[self updateLook];

glMultMatrixf(_attitudeMatrix.m);
_attitudeMatrix = GLKMatrix4Multiply([self getDeviceOrientationMatrix], _offsetMatrix);
[self updateLook];

glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, whiteColor); // panorama at full color
[sphere execute];
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, clearColor);
// [meridians execute]; // semi-transparent texture overlay (15° meridian lines)

//TODO: add any objects here to make them a part of the virtual reality
// glPushMatrix();
// // object code
// glPopMatrix();
glMultMatrixf(_attitudeMatrix.m);

// touch lines
if(_showTouches && _numberOfTouches){
glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
for(int i = 0; i < [[_touches allObjects] count]; i++){
glPushMatrix();
CGPoint touchPoint = CGPointMake([(UITouch*)[[_touches allObjects] objectAtIndex:i] locationInView:self].x,
[(UITouch*)[[_touches allObjects] objectAtIndex:i] locationInView:self].y);
[self drawHotspotLines:[self vectorFromScreenLocation:touchPoint inAttitude:_attitudeMatrix]];
glPopMatrix();
}
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, whiteColor); // panorama at full color
[sphere execute];
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, clearColor);
// [meridians execute]; // semi-transparent texture overlay (15° meridian lines)

//TODO: add any objects here to make them a part of the virtual reality
// glPushMatrix();
// // object code
// glPopMatrix();

// touch lines
if(_showTouches && _numberOfTouches){
glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
for(int i = 0; i < [[_touches allObjects] count]; i++){
glPushMatrix();
CGPoint touchPoint = CGPointMake([(UITouch*)[[_touches allObjects] objectAtIndex:i] locationInView:self].x,
[(UITouch*)[[_touches allObjects] objectAtIndex:i] locationInView:self].y);
[self drawHotspotLines:[self vectorFromScreenLocation:touchPoint inAttitude:_attitudeMatrix]];
glPopMatrix();
}
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}

glPopMatrix(); // end device orientation
}
Expand All @@ -202,25 +204,25 @@ -(GLKMatrix4) getDeviceOrientationMatrix{
// and combinations of 90 degree rotations (rows)
if(SENSOR_ORIENTATION == 4){
return GLKMatrix4Make( a.m21,-a.m11, a.m31, 0.0f,
a.m23,-a.m13, a.m33, 0.0f,
a.m23,-a.m13, a.m33, 0.0f,
-a.m22, a.m12,-a.m32, 0.0f,
0.0f , 0.0f , 0.0f , 1.0f);
0.0f , 0.0f , 0.0f , 1.0f);
}
if(SENSOR_ORIENTATION == 3){
return GLKMatrix4Make(-a.m21, a.m11, a.m31, 0.0f,
-a.m23, a.m13, a.m33, 0.0f,
a.m22,-a.m12,-a.m32, 0.0f,
0.0f , 0.0f , 0.0f , 1.0f);
a.m22,-a.m12,-a.m32, 0.0f,
0.0f , 0.0f , 0.0f , 1.0f);
}
if(SENSOR_ORIENTATION == 2){
return GLKMatrix4Make(-a.m11,-a.m21, a.m31, 0.0f,
-a.m13,-a.m23, a.m33, 0.0f,
a.m12, a.m22,-a.m32, 0.0f,
0.0f , 0.0f , 0.0f , 1.0f);
a.m12, a.m22,-a.m32, 0.0f,
0.0f , 0.0f , 0.0f , 1.0f);
}
return GLKMatrix4Make(a.m11, a.m21, a.m31, 0.0f,
a.m13, a.m23, a.m33, 0.0f,
-a.m12,-a.m22,-a.m32, 0.0f,
-a.m12,-a.m22,-a.m32, 0.0f,
0.0f , 0.0f , 0.0f , 1.0f);
}
else
Expand Down Expand Up @@ -261,10 +263,10 @@ -(GLKVector3) vectorFromScreenLocation:(CGPoint)point inAttitude:(GLKMatrix4)mat
GLKVector4 screen = GLKVector4Make(2.0*(point.x/self.frame.size.width-.5),
2.0*(.5-point.y/self.frame.size.height),
1.0, 1.0);
// if (SENSOR_ORIENTATION == 3 || SENSOR_ORIENTATION == 4)
// screen = GLKVector4Make(2.0*(screenTouch.x/self.frame.size.height-.5),
// 2.0*(.5-screenTouch.y/self.frame.size.width),
// 1.0, 1.0);
// if (SENSOR_ORIENTATION == 3 || SENSOR_ORIENTATION == 4)
// screen = GLKVector4Make(2.0*(screenTouch.x/self.frame.size.height-.5),
// 2.0*(.5-screenTouch.y/self.frame.size.width),
// 1.0, 1.0);
GLKVector4 vec = GLKMatrix4MultiplyVector4(inverse, screen);
return GLKVector3Normalize(GLKVector3Make(vec.x, vec.y, vec.z));
}
Expand All @@ -275,7 +277,7 @@ -(CGPoint) screenLocationFromVector:(GLKVector3)vector{
(0.5-screenVector.y/screenVector.z/2) * self.frame.size.height );
}
-(BOOL) computeScreenLocation:(CGPoint*)location fromVector:(GLKVector3)vector inAttitude:(GLKMatrix4)matrix{
//This method returns whether the point is before or behind the screen.
//This method returns whether the point is before or behind the screen.
GLKVector4 screenVector;
GLKVector4 vector4;
if(location == NULL)
Expand Down Expand Up @@ -335,10 +337,17 @@ -(void) panHandler:(UIPanGestureRecognizer*)sender{
else if([sender state] == 2){
GLKVector3 nowVector = [self vectorFromScreenLocation:[sender locationInView:sender.view] inAttitude:_offsetMatrix];
GLKQuaternion q = GLKQuaternionFromTwoVectors(touchVector, nowVector);
_offsetMatrix = GLKMatrix4Multiply(_offsetMatrix, GLKMatrix4MakeWithQuaternion(q));
// in progress for preventHeadTilt
// GLKMatrix4 mat = GLKMatrix4Multiply(_offsetMatrix, GLKMatrix4MakeWithQuaternion(q));
// _offsetMatrix = GLKMatrix4MakeLookAt(0, 0, 0, -mat.m02, -mat.m12, -mat.m22, 0, 1, 0);

if (_headTilt) {
_offsetMatrix = GLKMatrix4Multiply(_offsetMatrix, GLKMatrix4MakeWithQuaternion(q));
} else {
GLKMatrix4 lastMatrix = _offsetMatrix;
GLKMatrix4 mat = GLKMatrix4Multiply(_offsetMatrix, GLKMatrix4MakeWithQuaternion(q));
if (mat.m12 > self.yStop || mat.m12 < -self.yStop) {
mat = lastMatrix;
}
_offsetMatrix = GLKMatrix4MakeLookAt(0, 0, 0, -mat.m02, -mat.m12, -mat.m22, 0, 1, 0);
}
}
else{
_numberOfTouches = 0;
Expand Down Expand Up @@ -381,9 +390,9 @@ -(void) dealloc{
@end

@interface Sphere (){
// from Touch Fighter by Apple
// in Pro OpenGL ES for iOS
// by Mike Smithwick Jan 2011 pg. 78
// from Touch Fighter by Apple
// in Pro OpenGL ES for iOS
// by Mike Smithwick Jan 2011 pg. 78
GLKTextureInfo *m_TextureInfo;
GLfloat *m_TexCoordsData;
GLfloat *m_VertexData;
Expand Down