1. 首先開啓了一個新的專案
將OpenGL基本實作(九)的各個檔案複製過來,會如此作,實在是無法完成一個xcode的專案複製,並且修改專案的名稱,因此使用最愚蠢的方法了。其中的裡面的其他檔案名稱倒是不必更改。2. 從上向下修改,首先從GLSL的Simple.es2.vert開始
static const char* SimpleVertexShader = STRINGIFY(//To keep things simple, we'll use the infinite light source model for diffuse combined with the infinite viewer model for specular. We'll also assume that the light is white.
//vec3 ComputeLighting(vec3 normal)
//{
//N = NormalMatrix * normal
//L = Normalize(LightPosition)
//E = (0, 0, 1) 當觀眾在無限遠處時,E可以簡化成 [0, 0, 1]
//H = Normalize(L + E)
//df = max(0, N ∙ L) (df)DiffuseFactor = max(0, dot(N, L)) *** 0 <= df <= 1//sf = max(0, N ∙ H)
//sf = sf ^ Shininess
Specular Lighting
//return AmbientMaterial + DiffuseMaterial * df + SpecularMaterial * sf
//}
// 原來的項目,已不需要了,不再需要設定線條的顏色
//attribute vec4 SourceColor;
attribute vec4 Position; // 原來的項目
uniform mat4 Projection; // 原來的項目
uniform mat4 Modelview; // 原來的項目
varying vec4 DestinationColor; // 原來的項目
// 以下是光照項目的變數
attribute vec3 Normal; // 法線
attribute vec3 DiffuseMaterial; // 瀰漫
uniform mat3 NormalMatrix; // 法線矩陣
uniform vec3 LightPosition; // 照射位置
uniform vec3 AmbientMaterial; // 環境
uniform vec3 SpecularMaterial; // 鏡面
uniform float Shininess; // 反光
//use uniforms to store light position, specular and ambient properties.
void main(void)
{
vec3 N = NormalMatrix * Normal;
vec3 L = normalize(LightPosition);
vec3 E = vec3(0, 0, 1);
vec3 H = normalize(L + E);
float df = max(0.0, dot(N, L));
float sf = max(0.0, dot(N, H));
sf = pow(sf, Shininess);
vec3 color = AmbientMaterial + df * DiffuseMaterial + sf * SpecularMaterial;
//DestinationColor = SourceColor;
DestinationColor = vec4(color, 1); // replace
gl_Position = Projection * Modelview * Position;
}
);
3.mainViewController.mm加入六個Slider來作為調整光照的位置及小圖示的轉動方向。
#import "mainViewController.h"
@interface mainViewController ()
@end
@implementation mainViewController
{
UISlider *sIconXRotateSlider;
UISlider *sIconYRotateSlider;
UISlider *sIconZRotateSlider;
UISlider *lightPosXSlider;
UISlider *lightPosYSlider;
UISlider *lightPosZSlider;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CGRect screenBounds = [[UIScreen mainScreen] bounds];
m_window = [[UIWindow alloc] initWithFrame: screenBounds];
m_view = [[GLView alloc] initWithFrame: screenBounds];
[m_window addSubview: m_view];
[m_window makeKeyAndVisible];
[self setSlideInterface1];
[self setSlideInterface2];
[self setSlideInterface3];
[self setSlideInterfaceLightX];
[self setSlideInterfaceLightY];
[self setSlideInterfaceLightZ];
[m_window addSubview:sIconXRotateSlider];
[m_window addSubview:sIconYRotateSlider];
[m_window addSubview:sIconZRotateSlider];
[m_window addSubview:lightPosXSlider];
[m_window addSubview:lightPosYSlider];
[m_window addSubview:lightPosZSlider];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)shouldAutorotate{
return YES;
}
// 轉到Landscape 模式
-(NSInteger)supportedInterfaceOrientations{
// UIInterfaceOrientationMaskLandscape;
// 24
//
// UIInterfaceOrientationMaskLandscapeLeft;
// 16
//
// UIInterfaceOrientationMaskLandscapeRight;
// 8
//
// UIInterfaceOrientationMaskPortrait;
// 2
// return UIInterfaceOrientationMaskPortrait;
// or
return 24;
}
- (void)setSlideInterface1 {
sIconXRotateSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[sIconXRotateSlider setCenter:CGPointMake(50, 550)];//位置放在x=50, y=550的位置
[sIconXRotateSlider addTarget:self action:@selector(onSlider1ValueChange) forControlEvents:UIControlEventValueChanged];
sIconXRotateSlider.minimumValue = -1;
sIconXRotateSlider.maximumValue = 1;
sIconXRotateSlider.continuous = YES;
[sIconXRotateSlider setValue:0];
[self.view addSubview:sIconXRotateSlider];
}
- (void) onSlider1ValueChange
{
float myValue = sIconXRotateSlider.value;
m_view->smallIconRotateXValue = myValue;
//[m_view initSet:m_window.frame];
[m_view resetdisplayLink];
}
- (void)setSlideInterface2 {
sIconYRotateSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[sIconYRotateSlider setCenter:CGPointMake(50, 650)];//位置放在x=50, y=650的位置
[sIconYRotateSlider addTarget:self action:@selector(onSlider2ValueChange) forControlEvents:UIControlEventValueChanged];
sIconYRotateSlider.minimumValue = -1;
sIconYRotateSlider.maximumValue = 1;
sIconYRotateSlider.continuous = YES;
[sIconYRotateSlider setValue:0];
[self.view addSubview:sIconYRotateSlider];
}
- (void) onSlider2ValueChange
{
float myValue = sIconYRotateSlider.value;
m_view->smallIconRotateYValue = myValue;
//[m_view initSet:m_window.frame];
[m_view resetdisplayLink];
}
- (void)setSlideInterface3 {
sIconZRotateSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[sIconZRotateSlider setCenter:CGPointMake(50, 750)];//位置放在x=50, y=750的位置
[sIconZRotateSlider addTarget:self action:@selector(onSlider3ValueChange) forControlEvents:UIControlEventValueChanged];
sIconZRotateSlider.minimumValue = -1;
sIconZRotateSlider.maximumValue = 1;
sIconZRotateSlider.continuous = YES;
[sIconZRotateSlider setValue:0];
[self.view addSubview:sIconZRotateSlider];
}
- (void) onSlider3ValueChange
{
float myValue = sIconZRotateSlider.value;
m_view->smallIconRotateZValue = myValue;
//[m_view initSet:m_window.frame];
[m_view resetdisplayLink];
}
- (void)setSlideInterfaceLightX{
lightPosXSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
[lightPosXSlider setCenter:CGPointMake(600, 850)];//位置放在x=600, y=850的位置
[lightPosXSlider addTarget:self action:@selector(onSliderLinghtXValueChange) forControlEvents:UIControlEventValueChanged];
lightPosXSlider.minimumValue = -100;
lightPosXSlider.maximumValue = 100;
lightPosXSlider.continuous = YES;
[lightPosXSlider setValue:0.25];
[self.view addSubview:lightPosXSlider];
}
- (void) onSliderLinghtXValueChange
{
float myValue = lightPosXSlider.value;
m_view->lightPosX = myValue;
//[m_view initSet:m_window.frame];
[m_view resetdisplayLink];
}
- (void)setSlideInterfaceLightY{
lightPosYSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
[lightPosYSlider setCenter:CGPointMake(600, 900)];//位置放在x=600, y=900的位置
[lightPosYSlider addTarget:self action:@selector(onSliderLinghtYValueChange) forControlEvents:UIControlEventValueChanged];
lightPosYSlider.minimumValue = -100;
lightPosYSlider.maximumValue = 100;
lightPosYSlider.continuous = YES;
[lightPosYSlider setValue:0.25];
[self.view addSubview:lightPosYSlider];
}
- (void) onSliderLinghtYValueChange
{
float myValue = lightPosYSlider.value;
m_view->lightPosY = myValue;
//[m_view initSet:m_window.frame];
[m_view resetdisplayLink];
}
- (void)setSlideInterfaceLightZ{
lightPosZSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
[lightPosZSlider setCenter:CGPointMake(600, 950)];//位置放在x=600, y=950的位置
[lightPosZSlider addTarget:self action:@selector(onSliderLinghtZValueChange) forControlEvents:UIControlEventValueChanged];
lightPosZSlider.minimumValue = -100;
lightPosZSlider.maximumValue = 100;
lightPosZSlider.continuous = YES;
[lightPosZSlider setValue:1];
[self.view addSubview:lightPosZSlider];
}
- (void) onSliderLinghtZValueChange
{
float myValue = lightPosZSlider.value;
m_view->lightPosZ = myValue;
//[m_view initSet:m_window.frame];
[m_view resetdisplayLink];
}
@end
4. GLView.h 加入Slider對應的變數
#import <UIKit/UIKit.h>#import "Interfaces.hpp"
#import <QuartzCore/QuartzCore.h>
@interface GLView : UIView
{
@private
IApplicationEngine* m_applicationEngine;
IRenderingEngine* m_renderingEngine;
EAGLContext* m_context;
float m_timestamp;
@public
float smallIconRotateXValue;
float smallIconRotateYValue;
float smallIconRotateZValue;
float lightPosX;
float lightPosY;
float lightPosZ;
Quaternion old_orientation;
CADisplayLink* displayLink;
}
- (void) drawView: (CADisplayLink*) displayLink;
- (id) initSet:(CGRect) frame;
- (void) resetdisplayLink;
@end
5. GLView.mm 加入變數對應的控制碼
#import "GLView.h"
@implementation GLView
{
}
+ (Class) layerClass
{
return [CAEAGLLayer class];
}
- (id) initWithFrame: (CGRect) frame
{
smallIconRotateXValue =0;
smallIconRotateYValue =0;
smallIconRotateZValue =0;
lightPosX =0.25;
lightPosY =0.25;
lightPosZ =1;
old_orientation = Quaternion(0, 0, 0, 1);
if (self = [super initWithFrame:frame])
{
if ([self initSet:frame] == nil)
return nil;
}
return self;
}
- (id) initSet:(CGRect) frame
{
CAEAGLLayer* eaglLayer = (CAEAGLLayer*) self.layer;
eaglLayer.opaque = YES;
//EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES1;
m_context = [[EAGLContext alloc] initWithAPI:api];
if (!m_context) {
api = kEAGLRenderingAPIOpenGLES1;
m_context = [[EAGLContext alloc] initWithAPI:api];
}
if (!m_context || ![EAGLContext setCurrentContext:m_context]) {
//[self release];
return nil;
}
if (api == kEAGLRenderingAPIOpenGLES1) {
NSLog(@"Using OpenGL ES 1.1");
//m_renderingEngine = WireframeES1::CreateRenderingEngine();
m_renderingEngine = SolidES1::CreateRenderingEngine();
} else {
NSLog(@"Using OpenGL ES 2.0");
//m_renderingEngine = WireframeES2::CreateRenderingEngine(); // 完成 m_colorRenderbuffer 設定
m_renderingEngine = SolidES2::CreateRenderingEngine(); // replace
}
m_applicationEngine = ParametricViewer::CreateApplicationEngine(m_renderingEngine);
m_applicationEngine->SetIconRotateValue(smallIconRotateXValue, smallIconRotateYValue, smallIconRotateZValue);
[m_context
renderbufferStorage:GL_RENDERBUFFER
fromDrawable: eaglLayer];
int width = CGRectGetWidth(frame);
int height = CGRectGetHeight(frame);
m_applicationEngine->Initialize(width, height);
[self setdisplayLink];
return self;
}
- (void) setdisplayLink
{
[self drawView: nil];
m_timestamp = CACurrentMediaTime();
//CADisplayLink* displayLink;
displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(drawView:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
- (void) resetdisplayLink
{
displayLink = nil;
m_applicationEngine->SetIconRotateValue(smallIconRotateXValue, smallIconRotateYValue, smallIconRotateZValue);
[self drawView: nil];
m_timestamp = CACurrentMediaTime();
//CADisplayLink* displayLink;
displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(drawView:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
- (void) drawView: (CADisplayLink*) displayLink
{
if (displayLink != nil) {
m_applicationEngine->setLightPos(lightPosX, lightPosY, lightPosZ);
float elapsedSeconds = displayLink.timestamp - m_timestamp;
m_timestamp = displayLink.timestamp;
m_applicationEngine->UpdateAnimation(elapsedSeconds);
}
m_applicationEngine->Render();
[m_context presentRenderbuffer:GL_RENDERBUFFER];
}
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView: self];
m_applicationEngine->OnFingerDown(ivec2(location.x, location.y));
}
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView: self];
m_applicationEngine->OnFingerUp(ivec2(location.x, location.y)); //傳入所按的平面位置
}
- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
CGPoint previous = [touch previousLocationInView: self];
CGPoint current = [touch locationInView: self];
m_applicationEngine->OnFingerMove(ivec2(previous.x, previous.y),
ivec2(current.x, current.y));
}
@end
6. Interfaces.hpp 加入所需要的虛擬函數
#pragma once#include "Vector.hpp"
#include "Quaternion.hpp"
#include <vector>
#include <string>
using std::vector;
using std::string;
enum VertexFlags {
VertexFlagsNormals = 1 << 0, // ==1
VertexFlagsTexCoords = 1 << 1, // ==2
};
struct IApplicationEngine {
virtual void Initialize(int width, int height) = 0;
virtual void Render() const = 0;
virtual void UpdateAnimation(float timeStep) = 0;
virtual void OnFingerUp(ivec2 location) = 0;
virtual void OnFingerDown(ivec2 location) = 0;
virtual void OnFingerMove(ivec2 oldLocation, ivec2 newLocation) = 0;
virtual void SetIconRotateValue(float x, float y, float z) =0; // add for icon rotation
virtual void setLightPos(float x, float y, float z) = 0; // add for light position
virtual ~IApplicationEngine() {}
};
struct ISurface {
virtual int GetVertexCount() const = 0;
virtual int GetLineIndexCount() const = 0;
virtual int GetTriangleIndexCount() const = 0;
virtual void GenerateVertices(vector<float>& vertices,
unsigned char flags = 0) const = 0;
virtual void GenerateLineIndices(vector<unsigned short>& indices) const = 0;
virtual void GenerateTriangleIndices(vector<unsigned short>& indices) const = 0;
virtual ~ISurface() {}
};
struct Visual {
vec3 Color;
ivec2 LowerLeft;
ivec2 ViewportSize;
Quaternion Orientation;
};
struct IRenderingEngine {
virtual void Initialize(const vector<ISurface*>& surfaces) = 0;
virtual void Render(const vector<Visual>& visuals) const = 0;
virtual void setLightPos(float x, float y, float z) =0; //const = 0; /// 不能使用const
virtual ~IRenderingEngine() {}
};
// 此處的CreateApplicationEngine有重複到Function name,因此使用namespace
namespace ParametricViewer { IApplicationEngine* CreateApplicationEngine(IRenderingEngine*); }
//namespace ObjViewer { IApplicationEngine* CreateApplicationEngine(IRenderingEngine*, IResourceManager*); }
//namespace Darwin { IResourceManager* CreateResourceManager(); }
//namespace WireframeES1 { IRenderingEngine* CreateRenderingEngine(); }
//namespace WireframeES2 { IRenderingEngine* CreateRenderingEngine(); }
namespace SolidES1 { IRenderingEngine* CreateRenderingEngine(); }
namespace SolidES2 { IRenderingEngine* CreateRenderingEngine(); }
7. ApplicationEngine.ParametricViewer.cpp 計算放置3D Object的位置/方位及顏色
#include "Interfaces.hpp"
#include "ParametricEquations.hpp"
using namespace std;
namespace ParametricViewer {
static const int SurfaceCount = 6;
static const int ButtonCount = SurfaceCount - 1;
struct Animation {
bool Active;
float Elapsed;
float Duration;
Visual StartingVisuals[SurfaceCount];
Visual EndingVisuals[SurfaceCount];
};
// ApplicationEngine 公開繼承 IApplicationEngine,
class ApplicationEngine : public IApplicationEngine {
public:
ApplicationEngine(IRenderingEngine* renderingEngine);
~ApplicationEngine();
void Initialize(int width, int height);
void OnFingerUp(ivec2 location);
void OnFingerDown(ivec2 location);
void OnFingerMove(ivec2 oldLocation, ivec2 newLocation);
void Render() const;
void UpdateAnimation(float dt);
void SetIconRotateValue(float x, float y, float z);
void setLightPos(float x, float y, float z);
private:
void PopulateVisuals(Visual* visuals) const;
int MapToButton(ivec2 touchpoint) const;
vec3 MapToSphere(ivec2 touchpoint) const;
float m_trackballRadius;
ivec2 m_screenSize;
ivec2 m_centerPoint;
ivec2 m_fingerStart;
bool m_spinning;
Quaternion m_orientation;
Quaternion m_previousOrientation;
int m_currentSurface;
ivec2 m_buttonSize;
int m_pressedButton;
int m_buttonSurfaces[ButtonCount];
Animation m_animation;
IRenderingEngine* m_renderingEngine;
float smallIconRotateXValue;
float smallIconRotateYValue;
float smallIconRotateZValue;
float lightPosX;
float lightPosY;
float lightPosZ;
};
IApplicationEngine* CreateApplicationEngine(IRenderingEngine* renderingEngine)
{
return new ApplicationEngine(renderingEngine);
}
ApplicationEngine::ApplicationEngine(IRenderingEngine* renderingEngine) :
m_spinning(false),
m_pressedButton(-1),
m_renderingEngine(renderingEngine)
{
m_animation.Active = false;
m_buttonSurfaces[0] = 0;
m_buttonSurfaces[1] = 1;
m_buttonSurfaces[2] = 4;
m_buttonSurfaces[3] = 3;
m_buttonSurfaces[4] = 2;
m_currentSurface = 5;
}
ApplicationEngine::~ApplicationEngine()
{
delete m_renderingEngine;
}
void ApplicationEngine::Initialize(int width, int height)
{
m_trackballRadius = width / 3;
m_buttonSize.y = height / 10;
m_buttonSize.x = 4 * m_buttonSize.y / 3;
m_screenSize = ivec2(width, height - m_buttonSize.y);
m_centerPoint = m_screenSize / 2;
vector<ISurface*> surfaces(SurfaceCount);
surfaces[0] = new Cone(3, 1); // 設定半徑及高,其他
surfaces[1] = new Sphere(1.4f);
surfaces[2] = new Torus(1.4f, 0.3f);
surfaces[3] = new TrefoilKnot(1.8f);
surfaces[4] = new KleinBottle(0.2f);
surfaces[5] = new MobiusStrip(1);
m_renderingEngine->Initialize(surfaces);
for (int i = 0; i < SurfaceCount; i++)
delete surfaces[i];
}
void ApplicationEngine::PopulateVisuals(Visual* visuals) const
{
//設定所有圖像的顏色與大小,包含主圖及Button
for (int buttonIndex = 0; buttonIndex < ButtonCount; buttonIndex++) {
int visualIndex = m_buttonSurfaces[buttonIndex];
visuals[visualIndex].Color = vec3(0.25f*3, 0.25f, 0.25f); // Button上的顏色
if (m_pressedButton == buttonIndex)
visuals[visualIndex].Color = vec3(0.5f, 0.5f*3, 0.5f); // 點選後的Button顏色
// 設定每一個Button上的圖案大小
// visuals[visualIndex].ViewportSize = m_buttonSize;
// visuals[visualIndex].LowerLeft.x = buttonIndex * m_buttonSize.x;
// visuals[visualIndex].LowerLeft.y = 0;
// visuals[visualIndex].Orientation = Quaternion(); // 基本button的旋轉值為0
visuals[visualIndex].ViewportSize = m_buttonSize;
visuals[visualIndex].LowerLeft.x = 0;
visuals[visualIndex].LowerLeft.y = m_screenSize.y - buttonIndex * m_buttonSize.y ;
//visuals[visualIndex].Orientation = Quaternion(0,0,0,1); // 基本button的旋轉值為0
float angleValueX = smallIconRotateXValue; // -1 ~ 1 , 負值為順時鐘
float angleX = M_PI_2 *angleValueX;
float sinx = sin(angleX);
float cosx = cos(angleX);
float angleValueY = smallIconRotateYValue; // -1 ~ 1 , 負值為順時鐘
float angleY = M_PI_2 *angleValueY;
float siny = sin(angleY);
float cosy = cos(angleY);
float angleValueZ = smallIconRotateZValue; // -1 ~ 1 , 負值為順時鐘
float angleZ = M_PI_2 *angleValueZ;
float sinz = sin(angleZ);
float cosz = cos(angleZ);
Quaternion x = Quaternion(sinx*1,sinx*0, sinx*0, cosx);
Quaternion y = Quaternion(siny*0,siny*1, siny*0, cosy);
Quaternion z = Quaternion(sinz*0,sinz*0, sinz*1, cosz);
Quaternion xy = x.Rotated(y);
Quaternion xyz = xy.Rotated(z);
visuals[visualIndex].Orientation = xyz;
}
// 顯示主圖的顏色,m_spinning代表手指按下的狀態,蓋掉前面所設的值
visuals[m_currentSurface].Color = m_spinning ? vec3(1, 0, 0.75f) : vec3(1*3, 1, 0.5f);
visuals[m_currentSurface].LowerLeft = ivec2(0, m_buttonSize.y);
visuals[m_currentSurface].ViewportSize = ivec2(m_screenSize.x, m_screenSize.y);
visuals[m_currentSurface].Orientation = m_orientation; //主圖的旋轉值
}
void ApplicationEngine::Render() const
{
vector<Visual> visuals(SurfaceCount);
if (!m_animation.Active) {
PopulateVisuals(&visuals[0]);
} else {
float t = m_animation.Elapsed / m_animation.Duration;
for (int i = 0; i < SurfaceCount; i++) {
// 找出起始的visuals[x] 及最後的visuals[y]
const Visual& start = m_animation.StartingVisuals[i];
const Visual& end = m_animation.EndingVisuals[i];
Visual& tweened = visuals[i]; // 這時的 visuals[]中是空的
// 以下將所有的值重新填到新的visuals[]中,根據現在所見的狀態
tweened.Color = start.Color.Lerp(t, end.Color); //將顏色做線性插補取得時間變化值
tweened.LowerLeft = start.LowerLeft.Lerp(t, end.LowerLeft);
tweened.ViewportSize = start.ViewportSize.Lerp(t, end.ViewportSize);
tweened.Orientation = start.Orientation.Slerp(t, end.Orientation);
}
}
m_renderingEngine->setLightPos(lightPosX,lightPosY,lightPosZ);
m_renderingEngine->Render(visuals);
}
void ApplicationEngine::UpdateAnimation(float dt)
{
if (m_animation.Active) { // 改選成另一個物件
m_animation.Elapsed += dt;
if (m_animation.Elapsed > m_animation.Duration)
m_animation.Active = false;
}
}
void ApplicationEngine::SetIconRotateValue(float x, float y , float z)
{
smallIconRotateXValue = x;
smallIconRotateYValue = y;
smallIconRotateZValue = z;
}
void ApplicationEngine::setLightPos(float x, float y , float z)
{
lightPosX = x;
lightPosY = y;
lightPosZ = z;
}
// 3. 手指離開
void ApplicationEngine::OnFingerUp(ivec2 location)
{
m_spinning = false;
if (m_pressedButton != -1 && m_pressedButton == MapToButton(location) &&
!m_animation.Active) // 如果按選了其他的物件,就進行以下的程序
{
m_animation.Active = true;
m_animation.Elapsed = 0;
m_animation.Duration = 0.25f;
PopulateVisuals(&m_animation.StartingVisuals[0]);
swap(m_buttonSurfaces[m_pressedButton], m_currentSurface); // 點選的Button圖像與主圖像交換
PopulateVisuals(&m_animation.EndingVisuals[0]);
}
m_pressedButton = -1;
}
// 1. 壓下手指
void ApplicationEngine::OnFingerDown(ivec2 location)
{
m_fingerStart = location;
m_previousOrientation = m_orientation; // 取得現在的旋轉值
m_pressedButton = MapToButton(location);
if (m_pressedButton == -1)
m_spinning = true;
}
// 2. 移動手指讓物件轉動
void ApplicationEngine::OnFingerMove(ivec2 oldLocation, ivec2 location)
{
if (m_spinning) {
vec3 start = MapToSphere(m_fingerStart);
vec3 end = MapToSphere(location);
Quaternion delta = Quaternion::CreateFromVectors(start, end); // 取得方向向量
m_orientation = delta.Rotated(m_previousOrientation); // 根據前一個旋轉值,計算再次旋轉後的值,此為主圖所用
}
if (m_pressedButton != -1 && m_pressedButton != MapToButton(location))
m_pressedButton = -1;
}
// 確認所按的位置為主圖像的位置,並回傳所按的點,經計算後的3D位置。
vec3 ApplicationEngine::MapToSphere(ivec2 touchpoint) const
{
vec2 p = touchpoint - m_centerPoint;
// Flip the Y axis because pixel coords increase towards the bottom.
p.y = -p.y;
const float radius = m_trackballRadius;
const float safeRadius = radius - 1;
if (p.Length() > safeRadius) {
float theta = atan2(p.y, p.x);
p.x = safeRadius * cos(theta);
p.y = safeRadius * sin(theta);
}
float z = sqrt(radius * radius - p.LengthSquared());
vec3 mapped = vec3(p.x, p.y, z);
return mapped / radius;
}
/*
// 確認按到了Button 的位置,並回傳所按的Button代號。原始的
int ApplicationEngine::MapToButton(ivec2 touchpoint) const
{
if (touchpoint.y < m_screenSize.y - m_buttonSize.y)
return -1;
int buttonIndex = touchpoint.x / m_buttonSize.x;
if (buttonIndex >= ButtonCount)
return -1;
return buttonIndex;
}
*/
// 確認按到了Button 的位置,並回傳所按的Button代號。 修改後給 landscape用
int ApplicationEngine::MapToButton(ivec2 touchpoint) const
{
if (touchpoint.x > m_buttonSize.x)
return -1;
//m_screenSize.y - buttonIndex * m_buttonSize.y ;
int buttonIndex = (touchpoint.y) / m_buttonSize.y;
if (buttonIndex >= ButtonCount)
return -1;
return buttonIndex;
}
}
8. RenderingEngine.WireframeES1.cpp OPENGLES V1.1的主要呼叫程式碼
#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"
//namespace WireframeES1 {
namespace SolidES1 { // replace
struct Drawable {
GLuint VertexBuffer;
GLuint IndexBuffer;
int IndexCount;
};
class RenderingEngine : public IRenderingEngine {
public:
RenderingEngine();
void Initialize(const vector<ISurface*>& surfaces);
void Render(const vector<Visual>& visuals) const;
void setLightPos(float x, float y, float z); // const // 使用const就變成惟讀
private:
vector<Drawable> m_drawables;
GLuint m_colorRenderbuffer;
GLuint m_depthRenderbuffer; // new var
mat4 m_translation;
float lightPosX;
float lightPosY;
float lightPosZ;
};
IRenderingEngine* CreateRenderingEngine()
{
return new RenderingEngine();
}
RenderingEngine::RenderingEngine()
{
glGenRenderbuffersOES(1, &m_colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
}
void RenderingEngine::Initialize(const vector<ISurface*>& surfaces)
{
vector<ISurface*>::const_iterator surface;
for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
// Create the VBO for the vertices.
vector<float> vertices;
//(*surface)->GenerateVertices(vertices);
(*surface)->GenerateVertices(vertices, VertexFlagsNormals); // replace
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer); //設定GPU memory 給 Vertex用
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, // 將vertex資料存到GPU memory
vertices.size() * sizeof(vertices[0]), // 確認記憶體大小
&vertices[0],
GL_STATIC_DRAW);
// Create a new VBO for the indices if needed.
//int indexCount = (*surface)->GetLineIndexCount();
int indexCount = (*surface)->GetTriangleIndexCount();
GLuint indexBuffer;
if (!m_drawables.empty() && indexCount == m_drawables[0].IndexCount) {
indexBuffer = m_drawables[0].IndexBuffer;
} else {
vector<GLushort> indices(indexCount);
//(*surface)->GenerateLineIndices(indices); // 4個 indices為一組
(*surface)->GenerateTriangleIndices(indices); // replace
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indexCount * sizeof(GLushort),
&indices[0],
GL_STATIC_DRAW); // 表示该缓存区不会被修改
}
Drawable drawable = { vertexBuffer, indexBuffer, indexCount};
m_drawables.push_back(drawable);
}
// Extract width and height from the color buffer. new
int width, height;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_WIDTH_OES, &width);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_HEIGHT_OES, &height);
// Create a depth buffer that has the same size as the color buffer. new
glGenRenderbuffersOES(1, &m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,
width, height);
// Create the framebuffer object.
GLuint framebuffer;
glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES, m_colorRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, // new
GL_RENDERBUFFER_OES, m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
// Set up various GL state.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY); // new
glEnable(GL_LIGHTING); // new
glEnable(GL_LIGHT0); // new
glEnable(GL_DEPTH_TEST); // new
// Set up the material properties. // new
vec4 specular(0.5f, 0.5f, 0.5f, 1);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular.Pointer());
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.0f);
m_translation = mat4::Translate(0, 0, -7);
}
void RenderingEngine::Render(const vector<Visual>& visuals) const
{
glClearColor(0.5f, 0.5f, 0.5f, 1);
//glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // replace GL_DEPTH_BUFFER_BIT沒設到,會造成無法顯示
vector<Visual>::const_iterator visual = visuals.begin();
for (int visualIndex = 0; visual != visuals.end(); ++visual, ++visualIndex) {
// Set the viewport transform.
ivec2 size = visual->ViewportSize;
ivec2 lowerLeft = visual->LowerLeft;
glViewport(lowerLeft.x, lowerLeft.y, size.x, size.y);
// Set the light position. // new
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//vec4 lightPosition(0.25, 0.25, 1, 0);
vec4 lightPosition(lightPosX,lightPosY, lightPosZ,0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition.Pointer());
// Set the model-view transform.
mat4 rotation = visual->Orientation.ToMatrix();
mat4 modelview = rotation * m_translation;
glMatrixMode(GL_MODELVIEW); //指定哪一个矩阵是当前矩阵, GL_MODELVIEW/GL_PROJECTION/GL_TEXTURE
glLoadMatrixf(modelview.Pointer()); //
// Set the projection transform.
float h = 4.0f * size.y / size.x;
mat4 projection = mat4::Frustum(-2, 2, -h / 2, h / 2, 5, 10);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projection.Pointer());
// Set the diffuse color. //new
vec3 color = visual->Color * 0.75f;
vec4 diffuse(color.x, color.y, color.z, 1);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse.Pointer());
// // Draw the wireframe.
// int stride = sizeof(vec3);
// const Drawable& drawable = m_drawables[visualIndex];
// glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
// glVertexPointer(3, GL_FLOAT, stride, 0);
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
// glDrawElements(GL_LINES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
// Draw the surface. // new and renew
int stride = 2 * sizeof(vec3);
const GLvoid* normalOffset = (const GLvoid*) sizeof(vec3);
const Drawable& drawable = m_drawables[visualIndex];
glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
glVertexPointer(3, GL_FLOAT, stride, 0);
glNormalPointer(GL_FLOAT, stride, normalOffset);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
}
}
void RenderingEngine::setLightPos(float x, float y, float z) // const // 使用const就變成惟讀函數
{
lightPosX = x;
lightPosY = y;
lightPosZ = z;
}
}
9. RenderingEngine.WireframeES2.cpp OPENGLES V2.0的主要呼叫程式碼
#include <OpenGLES/ES2/gl.h>#include <OpenGLES/ES2/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"
#include <iostream>
namespace SolidES2 {
//WireframeES2 {
#define STRINGIFY(A) #A
#include "./Shaders/Simple.es2.vert"
#include "./Shaders/Simple.es2.frag"
struct UniformHandles { // new 專門處理 Simple.es2.vert 中 uniform 的變數
GLuint Modelview;
GLuint Projection;
GLuint NormalMatrix;
GLuint LightPosition;
GLint AmbientMaterial;
GLint SpecularMaterial;
GLint Shininess;
};
struct AttributeHandles { // new 專門處理 Simple.es2.vert 中 attribute 的變數
GLint Position;
GLint Normal;
GLint DiffuseMaterial;
};
struct Drawable {
GLuint VertexBuffer;
GLuint IndexBuffer;
int IndexCount;
};
class RenderingEngine : public IRenderingEngine {
public:
RenderingEngine();
void Initialize(const vector<ISurface*>& surfaces);
void Render(const vector<Visual>& visuals) const;
void setLightPos(float x, float y, float z) ; // const // 使用const就變成惟讀
private:
GLuint BuildShader(const char* source, GLenum shaderType) const;
GLuint BuildProgram(const char* vShader, const char* fShader) const;
vector<Drawable> m_drawables;
GLuint m_colorRenderbuffer;
GLuint m_depthRenderbuffer; //new and replace
//GLint m_projectionUniform;
//GLint m_modelviewUniform;
//GLuint m_positionSlot;
//GLuint m_colorSlot;
mat4 m_translation;
UniformHandles m_uniforms; // new 改成用struct 模式來控制 GLSL 檔中的uniform 變數
AttributeHandles m_attributes; // new 改成用struct 模式來控制 GLSL 檔中的 attribute 變數
float lightPosX;
float lightPosY;
float lightPosZ;
};
IRenderingEngine* CreateRenderingEngine()
{
return new RenderingEngine();
}
RenderingEngine::RenderingEngine()
{
glGenRenderbuffers(1, &m_colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
}
void RenderingEngine::Initialize(const vector<ISurface*>& surfaces)
{
vector<ISurface*>::const_iterator surface;
for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
// Create the VBO for the vertices.
vector<float> vertices;
//(*surface)->GenerateVertices(vertices);
(*surface)->GenerateVertices(vertices, VertexFlagsNormals); // new / replace
//Tell the ParametricSurface object that we need normals by passing in the new VertexFlagsNormals flag.
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER,
vertices.size() * sizeof(vertices[0]),
&vertices[0],
GL_STATIC_DRAW);
// Create a new VBO for the indices if needed.
//int indexCount = (*surface)->GetLineIndexCount();
int indexCount = (*surface)->GetTriangleIndexCount(); // replace 改成三角形處理,數量不同
GLuint indexBuffer;
if (!m_drawables.empty() && indexCount == m_drawables[0].IndexCount) {
indexBuffer = m_drawables[0].IndexBuffer;
} else {
vector<GLushort> indices(indexCount);
//(*surface)->GenerateLineIndices(indices);
(*surface)->GenerateTriangleIndices(indices); // replace 改成三角形處理,
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indexCount * sizeof(GLushort),
&indices[0],
GL_STATIC_DRAW);
}
Drawable drawable = { vertexBuffer, indexBuffer, indexCount};
m_drawables.push_back(drawable); // 新增drawable至 m_drawables 的尾端,必要時會進行記憶體配置。
}
// Extract width and height. new
int width, height;
glGetRenderbufferParameteriv(GL_RENDERBUFFER,
GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER,
GL_RENDERBUFFER_HEIGHT, &height);
// Create a depth buffer that has the same size as the color buffer. new
glGenRenderbuffers(1, &m_depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
// Create the framebuffer object. (FBO)
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// 设置FrameBuffer并使用glFramebufferRenderBuffer相互关联
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, //
GL_RENDERBUFFER, m_colorRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, // new
GL_RENDERBUFFER, m_depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
// Create the GLSL program. // replace
GLuint program = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
glUseProgram(program);
// Create the GLSL program.
//GLuint simpleProgram = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
//glUseProgram(simpleProgram);
// m_positionSlot = glGetAttribLocation(simpleProgram, "Position");
// m_colorSlot = glGetAttribLocation(simpleProgram, "SourceColor");
// glEnableVertexAttribArray(m_positionSlot);
//
// Extract the handles to attributes and uniforms. replace
m_attributes.Position = glGetAttribLocation(program, "Position");
m_attributes.Normal = glGetAttribLocation(program, "Normal");
m_attributes.DiffuseMaterial = glGetAttribLocation(program, "DiffuseMaterial");
m_uniforms.Projection = glGetUniformLocation(program, "Projection");
m_uniforms.Modelview = glGetUniformLocation(program, "Modelview");
m_uniforms.NormalMatrix = glGetUniformLocation(program, "NormalMatrix");
m_uniforms.LightPosition = glGetUniformLocation(program, "LightPosition");
m_uniforms.AmbientMaterial = glGetUniformLocation(program, "AmbientMaterial");
m_uniforms.SpecularMaterial = glGetUniformLocation(program, "SpecularMaterial");
m_uniforms.Shininess = glGetUniformLocation(program, "Shininess");
// Set up some default material parameters. // replace
glUniform3f(m_uniforms.AmbientMaterial, 0.04f, 0.04f, 0.04f);
glUniform3f(m_uniforms.SpecularMaterial, 0.5, 0.5, 0.5);
glUniform1f(m_uniforms.Shininess, 50);
// // Set up some matrices.
// m_translation = mat4::Translate(0, 0, -7);
// m_projectionUniform = glGetUniformLocation(simpleProgram, "Projection");
// m_modelviewUniform = glGetUniformLocation(simpleProgram, "Modelview");
// Initialize various state. // replace
glEnableVertexAttribArray(m_attributes.Position);
glEnableVertexAttribArray(m_attributes.Normal);
glEnable(GL_DEPTH_TEST);
// Set up transforms. (change line position)
m_translation = mat4::Translate(0, 0, -7);
}
void RenderingEngine::Render(const vector<Visual>& visuals) const
{
glClearColor(0.5f, 0.5f, 0.5f, 1);
//glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // replace
vector<Visual>::const_iterator visual = visuals.begin();
// 將所有的圖像都畫出,Button上的圖像,使用相對小的Size(64,48), 主圖大小為(320,432)
// 0~5, 5指的是主畫面
for (int visualIndex = 0; visual != visuals.end(); ++visual, ++visualIndex) {
// Set the viewport transform.
ivec2 size = visual->ViewportSize;
ivec2 lowerLeft = visual->LowerLeft;
glViewport(lowerLeft.x, lowerLeft.y, size.x, size.y);
// Set the light position. // new
//vec4 lightPosition(0.25, 0.25, 1, 0);
vec4 lightPosition(lightPosX,lightPosY, lightPosZ,0);
glUniform3fv(m_uniforms.LightPosition, 1, lightPosition.Pointer());
// Set the model-view transform.
mat4 rotation = visual->Orientation.ToMatrix(); // 只有主圖像的旋轉四元值被讀入,並轉為矩陣。
mat4 modelview = rotation * m_translation; // m_translation =[0,0, -7]
//glUniformMatrix4fv(m_modelviewUniform, 1, 0, modelview.Pointer());
glUniformMatrix4fv(m_uniforms.Modelview, 1, 0, modelview.Pointer()); // replace
// Set the normal matrix. new
// It's orthogonal, so its Inverse-Transpose is itself!
mat3 normalMatrix = modelview.ToMat3();
glUniformMatrix3fv(m_uniforms.NormalMatrix, 1, 0, normalMatrix.Pointer());
// Set the projection transform.
float h = 4.0f * size.y / size.x;
mat4 projectionMatrix = mat4::Frustum(-2, 2, -h / 2, h / 2, 5, 10);
//glUniformMatrix4fv(m_projectionUniform, 1, 0, projectionMatrix.Pointer());
glUniformMatrix4fv(m_uniforms.Projection, 1, 0, projectionMatrix.Pointer()); // replace
// Set the color.
// vec3 color = visual->Color;
// glVertexAttrib4f(m_colorSlot, color.x, color.y, color.z, 1);
//
// Set the diffuse color. // new and replace
vec3 color = visual->Color * 0.75f;
glVertexAttrib4f(m_attributes.DiffuseMaterial, color.x, color.y, color.z, 1);
// Draw the wireframe.
//int stride = sizeof(vec3);
//const Drawable& drawable = m_drawables[visualIndex];
//glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
//glVertexAttribPointer(m_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, 0);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
//glDrawElements(GL_LINES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
// Draw the surface. // new and replace
int stride = 2 * sizeof(vec3); // replace
const GLvoid* offset = (const GLvoid*) sizeof(vec3); // new
GLint position = m_attributes.Position; // new
GLint normal = m_attributes.Normal; // new
const Drawable& drawable = m_drawables[visualIndex];
glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, stride, 0); // replace
glVertexAttribPointer(normal, 3, GL_FLOAT, GL_FALSE, stride, offset); // new
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0); // replace , use triangles
}
}
GLuint RenderingEngine::BuildShader(const char* source, GLenum shaderType) const
{
GLuint shaderHandle = glCreateShader(shaderType);
glShaderSource(shaderHandle, 1, &source, 0);
glCompileShader(shaderHandle);
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
std::cout << messages;
exit(1);
}
return shaderHandle;
}
GLuint RenderingEngine::BuildProgram(const char* vertexShaderSource,
const char* fragmentShaderSource) const
{
GLuint vertexShader = BuildShader(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fragmentShader = BuildShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
GLuint programHandle = glCreateProgram();
glAttachShader(programHandle, vertexShader);
glAttachShader(programHandle, fragmentShader);
glLinkProgram(programHandle);
GLint linkSuccess;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
std::cout << messages;
exit(1);
}
return programHandle;
}
void RenderingEngine::setLightPos(float x, float y, float z) // const // 使用const就變成惟讀
{
lightPosX = x;
lightPosY = y;
lightPosZ = z;
}
}
10. 結果,分別為啓動原始圖、調整光照的位置及轉動小圖中物件的方向
PS:在此表面運算使用三角運算取代線條
void ParametricSurface::GenerateLineIndices(vector<unsigned short>& indices) const
{
indices.resize(GetLineIndexCount());
vector<unsigned short>::iterator index = indices.begin();
for (int j = 0, vertex = 0; j < m_slices.y; j++) {
for (int i = 0; i < m_slices.x; i++) {
int next = (i + 1) % m_divisions.x;
*index++ = vertex + i;
*index++ = vertex + next;
*index++ = vertex + i;
*index++ = vertex + i + m_divisions.x;
}
vertex += m_divisions.x;
}
}
void
ParametricSurface::GenerateTriangleIndices(vector<unsigned short>& indices) const
{
indices.resize(GetTriangleIndexCount());
vector<unsigned short>::iterator index = indices.begin();
for (int j = 0, vertex = 0; j < m_slices.y; j++) {
for (int i = 0; i < m_slices.x; i++) { // 此處要看上圖所繪,兩個三角形的點,故有六個
int next = (i + 1) % m_divisions.x;
*index++ = vertex + i;
*index++ = vertex + next; //重複
*index++ = vertex + i + m_divisions.x; //重複
*index++ = vertex + next; //重複
*index++ = vertex + next + m_divisions.x;
*index++ = vertex + i + m_divisions.x; //重複
}
vertex += m_divisions.x;
}
}






