在此例中加入額外的X方向轉動。
其中背面剔除這個做法,幾乎都使用默認值,比較難以理解。
1. StoryBoard修改成一樣的架構,原有的放到旁邊去,這樣一個專案可以給兩個測試並用。
2. 加入一個新的OpenGLView2,作為顯示結果,原有的保留。本來要改成同時執行兩個OPENGL,後來研究發現iOS並不支援,因此將原來的OpenGLView 的instance,給它mark起來。
OpenGLView2.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#import "ksMatrix.h"
@interface OpenGLView2 : UIView {
CAEAGLLayer* _eaglLayer;
EAGLContext* _context;
GLuint _colorRenderBuffer;
GLuint _frameBuffer;
GLuint _programHandle;
GLuint _positionSlot;
GLuint _modelViewSlot;
GLuint _projectionSlot;
GLuint _colorSlot;
ksMatrix4 _modelViewMatrix;
ksMatrix4 _projectionMatrix;
float _rotateShoulder;
float _rotateElbow;
float _xRotateShoulder;
}
@property (nonatomic, assign) float rotateShoulder;
@property (nonatomic, assign) float rotateElbow;
@property (nonatomic, assign) float xRotateShoulder;
- (void)render;
- (void)cleanup;
- (void)toggleDisplayLink;
@end
OpenGLView2.m
#import "OpenGLView2.h"
#import "GLESUtils.h"
// Declare private members inside anonymous category
@interface OpenGLView2()
{
ksMatrix4 _shouldModelViewMatrix;
ksMatrix4 _elbowModelViewMatrix;
float _rotateColorCube;
CADisplayLink * _displayLink;
}
- (void)setupLayer;
- (void)setupContext;
- (void)setupBuffers;
- (void)destoryBuffers;
- (void)setupProgram;
- (void)setupProjection;
- (void)updateShoulderTransform;
- (void)updateElbowTransform;
- (void)resetTransform;
- (void)updateRectangleTransform;
- (void)updateColorCubeTransform;
- (void)drawColorCube;
- (void)drawCube:(ksColor) color;
@end
@implementation OpenGLView2
@synthesize rotateShoulder = _rotateShoulder;
@synthesize rotateElbow = _rotateElbow;
@synthesize xRotateShoulder = _xRotateShoulder;
+ (Class)layerClass {
// Support for OpenGL ES
return [CAEAGLLayer class];
}
- (void)setupLayer
{
_eaglLayer = (CAEAGLLayer*) self.layer;
// Make CALayer visibale
_eaglLayer.opaque = YES;
// Set drawable properties
_eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
}
- (void)setupContext {
// Set OpenGL version, here is OpenGL ES 2.0
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
if (!_context) {
NSLog(@" >> Error: Failed to initialize OpenGLES 2.0 context");
exit(1);
}
// Set OpenGL context
if (![EAGLContext setCurrentContext:_context]) {
_context = nil;
NSLog(@" >> Error: Failed to set current OpenGL context");
exit(1);
}
}
- (void)setupBuffers {
glGenRenderbuffers(1, &_colorRenderBuffer);
// Set as current renderbuffer
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
// Allocate color renderbuffer
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
glGenFramebuffers(1, &_frameBuffer);
// Set as current framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
// Attach _colorRenderBuffer to _frameBuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, _colorRenderBuffer);
}
- (void)destoryBuffers
{
glDeleteRenderbuffers(1, &_colorRenderBuffer);
_colorRenderBuffer = 0;
glDeleteFramebuffers(1, &_frameBuffer);
_frameBuffer = 0;
}
- (void)cleanup
{
[self destoryBuffers];
if (_programHandle != 0) {
glDeleteProgram(_programHandle);
_programHandle = 0;
}
if (_context && [EAGLContext currentContext] == _context)
[EAGLContext setCurrentContext:nil];
_context = nil;
}
- (void)setupProgram
{
// Load shaders
//
NSString * vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"VertexShader2"
ofType:@"glsl"];
NSString * fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader2"
ofType:@"glsl"];
_programHandle = [GLESUtils loadProgram:vertexShaderPath
withFragmentShaderFilepath:fragmentShaderPath];
if (_programHandle == 0) {
NSLog(@" >> Error: Failed to setup program.");
return;
}
glUseProgram(_programHandle);
// Get the attribute position slot from program
//
_positionSlot = glGetAttribLocation(_programHandle, "vPosition");
// Get the attribute color slot from program
//
_colorSlot = glGetAttribLocation(_programHandle, "vSourceColor");
// Get the uniform model-view matrix slot from program
//
_modelViewSlot = glGetUniformLocation(_programHandle, "modelView");
// Get the uniform projection matrix slot from program
//
_projectionSlot = glGetUniformLocation(_programHandle, "projection");
}
-(void)setupProjection
{
// Generate a perspective matrix with a 60 degree FOV
//
float aspect = self.frame.size.width / self.frame.size.height;
ksMatrixLoadIdentity(&_projectionMatrix);
ksPerspective(&_projectionMatrix, 60.0, aspect, 1.0f, 20.0f);
// Load projection matrix
glUniformMatrix4fv(_projectionSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
glEnable(GL_CULL_FACE);
}
- (void) updateShoulderTransform
{
ksMatrixLoadIdentity(&_shouldModelViewMatrix);
ksMatrixTranslate(&_shouldModelViewMatrix, -0.0, 0.0, -5.5);
// Rotate the shoulder
//
ksMatrixRotate(&_shouldModelViewMatrix, self.rotateShoulder, 0.0, 0.0, 1.0);
ksMatrixRotate(&_shouldModelViewMatrix, self.xRotateShoulder, 1.0, 0.0, 0.0);
// Scale the cube to be a shoulder
//
ksMatrixCopy(&_modelViewMatrix, &_shouldModelViewMatrix);
ksMatrixScale(&_modelViewMatrix, 1.5, 0.6, 0.6);
// Load the model-view matrix
glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
}
- (void) updateElbowTransform
{
// Relative to shoulder
//
ksMatrixCopy(&_elbowModelViewMatrix, &_shouldModelViewMatrix);
// Translate away from shoulder
//
ksMatrixTranslate(&_elbowModelViewMatrix, 1.5, 0.0, 0.0);
// Rotate the elbow
//
ksMatrixRotate(&_elbowModelViewMatrix, self.rotateElbow, 0.0, 0.0, 1.0);
// Scale the cube to be a elbow
ksMatrixCopy(&_modelViewMatrix, &_elbowModelViewMatrix);
ksMatrixScale(&_modelViewMatrix, 1.0, 0.4, 0.4);
// Load the model-view matrix
glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
}
- (void)drawCube:(ksColor) color
{
GLfloat vertices[] = {
0.0f, -0.5f, 0.5f,
0.0f, 0.5f, 0.5f,
1.0f, 0.5f, 0.5f,
1.0f, -0.5f, 0.5f,
1.0f, -0.5f, -0.5f,
1.0f, 0.5f, -0.5f,
0.0f, 0.5f, -0.5f,
0.0f, -0.5f, -0.5f,
};
GLubyte indices[] = {
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 7, 1, 6, 2, 5, 3, 4
};
glVertexAttrib4f(_colorSlot, color.r, color.g, color.b, color.a);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
glEnableVertexAttribArray(_positionSlot);
glDrawElements(GL_LINES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
}
- (void) updateRectangleTransform
{
ksMatrixLoadIdentity(&_modelViewMatrix);
ksMatrixTranslate(&_modelViewMatrix, 0.0, -2, -5.5);
// Load the model-view matrix
glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
}
- (void)drawColorRectangle
{
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f, 1.0, 0.0, 0.0, 1.0,
-0.5f, 0.5f, 0.0f, 0.0, 0.0, 1.0, 1.0,
0.5f, 0.5f, 0.0f, 1.0, 1.0, 0.0, 1.0,
0.5f, -0.5f, 0.0f, 1.0, 1.0, 1.0, 1.0
};
GLubyte indices[] = {
0, 3, 2,
0, 2, 1
};
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), vertices);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), vertices + 3);
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
glDisableVertexAttribArray(_colorSlot);
}
- (void) updateColorCubeTransform
{
ksMatrixLoadIdentity(&_modelViewMatrix);
ksMatrixTranslate(&_modelViewMatrix, 0.0, -2, -5.5);
ksMatrixRotate(&_modelViewMatrix, _rotateColorCube, 0.0, 1.0, 0.0);
// Load the model-view matrix
glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
}
- (void) drawColorCube
{
GLfloat vertices[] = {
-0.5f, -0.5f, 0.5f, 1.0, 0.0, 0.0, 1.0, // red
-0.5f, 0.5f, 0.5f, 1.0, 1.0, 0.0, 1.0, // yellow
0.5f, 0.5f, 0.5f, 0.0, 0.0, 1.0, 1.0, // blue
0.5f, -0.5f, 0.5f, 1.0, 1.0, 1.0, 1.0, // white
0.5f, -0.5f, -0.5f, 1.0, 1.0, 0.0, 1.0, // yellow
0.5f, 0.5f, -0.5f, 1.0, 0.0, 0.0, 1.0, // red
-0.5f, 0.5f, -0.5f, 1.0, 1.0, 1.0, 1.0, // white
-0.5f, -0.5f, -0.5f, 0.0, 0.0, 1.0, 1.0, // blue
};
GLubyte indices[] = {
// Front face
0, 3, 2, 0, 2, 1,
// Back face
7, 5, 4, 7, 6, 5,
// Left face
0, 1, 6, 0, 6, 7,
// Right face
3, 4, 5, 3, 5, 2,
// Up face
1, 2, 5, 1, 5, 6,
// Down face
0, 7, 4, 0, 4, 3
};
// 說明:
// a. Position 資料是位於 struct 的起始處, 因此偏移量為: 0.
// b. Color 資料是位於 Position 資料之後, 因此偏移量為: sizeof(float) * 3.
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), vertices);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), vertices + 3);
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
glDisableVertexAttribArray(_colorSlot);
}
- (void)render
{
if (_context == nil)
return;
ksColor colorRed = {1, 0, 0, 1};
ksColor colorWhite = {1, 1, 1, 1};
glClearColor(0.0, 1.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// Setup viewport
//
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
// Draw color rectangle
//
// [self updateRectangleTransform];
// [self drawColorRectangle];
// Draw color cube
//
[self updateColorCubeTransform];
[self drawColorCube];
// Draw shoulder
//
[self updateShoulderTransform];
[self drawCube:colorRed];
// Draw elbow
//
[self updateElbowTransform];
[self drawCube:colorWhite];
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self setupLayer];
[self setupContext];
[self setupProgram];
[self setupProjection];
[self resetTransform];
}
return self;
}
- (void)layoutSubviews
{
[EAGLContext setCurrentContext:_context];
glUseProgram(_programHandle);
[self destoryBuffers];
[self setupBuffers];
[self render];
}
#pragma mark - Transform properties
- (void)resetTransform
{
self.rotateShoulder = 0.0;
self.rotateElbow = 0.0;
[self updateShoulderTransform];
[self updateElbowTransform];
}
- (void)setRotateShoulder:(float)rotateShoulder
{
_rotateShoulder = rotateShoulder;
[self render];
}
- (float)rotateShoulder
{
return _rotateShoulder;
}
- (void)setRotateElbow:(float)rotateElbow
{
_rotateElbow = rotateElbow;
[self render];
}
- (float)rotateElbow
{
return _rotateElbow;
}
- (void)setXRotateShoulder:(float)xRotateShoulder
{
_xRotateShoulder = xRotateShoulder;
[self render];
}
- (float)xRotateShoulder
{
return _xRotateShoulder;
}
- (void)toggleDisplayLink
{
if (_displayLink == nil) {
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
else {
[_displayLink invalidate];
[_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
_displayLink = nil;
}
}
- (void)displayLinkCallback:(CADisplayLink*)displayLink
{
_rotateColorCube += displayLink.duration * 90;
[self render];
}
#pragma mark
@end
3. 參考上圖,另外加入VertexShader2.glsl及FragmentShader2.glsl。原有的保留不用。
FragmentShader2.glsl
precision mediump float;
varying vec4 vDestinationColor;
void main()
{
gl_FragColor = vDestinationColor; // 設定顏色之處
}
VertexShader2.glsl
uniform mat4 projection;
uniform mat4 modelView;
attribute vec4 vPosition;
attribute vec4 vSourceColor;
varying vec4 vDestinationColor;
void main(void)
{
gl_Position = projection * modelView * vPosition;
vDestinationColor = vSourceColor;
}
4. 修改mainViewController.h
#import <UIKit/UIKit.h>
#import "OpenGLView.h"
#import "OpenGLView2.h"
@interface mainViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *controlView;
//@property (strong, nonatomic) IBOutlet OpenGLView *openGLView;
@property (strong, nonatomic) IBOutlet OpenGLView2 *openGLView2;
@property (strong, nonatomic) IBOutlet UISlider *posXSlider;
@property (strong, nonatomic) IBOutlet UISlider *posYSlider;
@property (strong, nonatomic) IBOutlet UISlider *posZSlider;
@property (strong, nonatomic) IBOutlet UISlider *scaleZSlider;
@property (strong, nonatomic) IBOutlet UISlider *rotateXSlider;
@property (strong, nonatomic) IBOutlet UISlider *rotateYSlider;
@end
5. 修改 mainViewController.m
//@synthesize openGLView;
@synthesize openGLView2;
- (IBAction)shouderRotate:(id)sender {
UISlider * slider = (UISlider *)sender;
float currentValue = [slider value];
NSLog(@" >> current shoulder is %f", currentValue);
self.openGLView2.rotateShoulder = currentValue;
}
- (IBAction)elbowRotate:(id)sender {
UISlider * slider = (UISlider *)sender;
float currentValue = [slider value];
NSLog(@" >> current elbow is %f", currentValue);
self.openGLView2.rotateElbow = currentValue;
}
- (IBAction)shouderXRotate:(id)sender {
UISlider * slider = (UISlider *)sender;
float currentValue = [slider value];
NSLog(@" >> current shoulder is %f", currentValue);
self.openGLView2.xRotateShoulder = currentValue;
}
- (IBAction)cubeRotate:(id)sender {
[self.openGLView2 toggleDisplayLink];
UIButton * button = (UIButton *)sender;
NSString * text = button.titleLabel.text;
if ([text isEqualToString:@"Rotate"]) {
[button setTitle: @"Stop" forState: UIControlStateNormal];
}
else {
[button setTitle: @"Rotate" forState: UIControlStateNormal];
}
}
6. 結果



沒有留言:
張貼留言