一、坐标系统
顶点坐标变换是所有的顶点程序所必须实现的任务之一。因为光栅化需要被变换的坐标来装配图元和产生片断。
图一显示了用于处理顶点坐标的传统变换。图示解释了坐标从某种坐标空间的一种变换到下一个变换之间的转变。
图一 坐标系统和用于顶点处理的变换
对象空间
应用程序制定顶点位置是在被称为对象空间(object space)或者模型空间(model space)中。一个对象的对象空间经常和另外一个对象的对象空间无关。
世界空间
世界坐标空间的目的是为了提供不同对象之间的相对关系。通过模型变换可以从对象空间变换为世界空间。所有的变换都可以用一个4*4的矩阵来表示。通过把这些矩阵相乘,可以把这些变换连在一起。这将会很有用。
视图空间
典型的视图变换包含了这样的一个平移:把世界坐标空间中的眼睛的位置移到视图空间的原点,然后适当旋转眼睛。
大多数的光照和渲染计算需要比如坐标、表面法线等属性。一般,这些计算在视图空间或者对象空间中进行会更加有效率。在一个场景中,世界坐标空间对于应用程序建立各不同的对象之间的空间关系很有用。但是对于计算光照和其他渲染则效率不高。因此,我们把代表模型和视图变换的两个矩阵合成一个矩阵:模型视图矩阵:用模型矩阵乘以视图矩阵即可。
剪切空间
Cg顶点程序输出的顶点坐标是剪切空间中的坐标,而且必须输出一个剪切空间的坐标。POSITION语意就代表一个顶点程序的特定的输出是剪切空间坐标。
把视图空间的坐标变换为剪切空间的坐标的变换成为投影变换。
OpenGL和DirectX对于剪切空间有着不同的规则定义。在OpenGL中,可见的物体必须在一个坐标轴对其的立方体中:剪切空间坐标的x、y和z分量必须小于或者等于w分量,即:-w<=x<=w,-w<=y<=w,-w<=z<=w。
图二显示了投影矩阵如何把视图空间中的机器人变换到剪切空间中。
图二 投影矩阵的作用
剪切空间的坐标是齐次坐标形式<x,y,z,w>。
但是我们需要计算2D坐标和相应的深度值。
规范化设备坐标
通过透视除法获得规范化设备坐标。这样所有可见的几何数据都在一个立方体里面:坐标在<-1,-1,-1>和<1,1,1>之间(在OpenGL中)。
视口变换
变换为窗口坐标。
二、原理应用
Cg顶点程序通常接受的是对象空间中的顶点坐标。
图三显示了把对象坐标变换为剪切坐标的两种方式:
图三 变换到剪切空间中
三、程序实例(OpenGL + Cg + C++):
程序绘制了一个不断旋转的网格状球体。
顶点Cg程序vertex.cg:
[cpp] view plain copy print ?
- struct output_v{
- float4 oPosition : POSITION;
- float3 color : COLOR;
- };
-
- output_v main_v(float4 position : POSITION,
- float3 color : COLOR,
- uniform float4x4 modelViewProj)
- {
- output_v OUT;
-
- modelViewProj = glstate.matrix.mvp;
-
- OUT.oPosition = mul(modelViewProj,position);
- OUT.color = color;
-
- return OUT;
- }
struct output_v{
float4 oPosition : POSITION;
float3 color : COLOR;
};
output_v main_v(float4 position : POSITION,
float3 color : COLOR,
uniform float4x4 modelViewProj)
{
output_v OUT;
// Get OpenGL state matrices
modelViewProj = glstate.matrix.mvp;
// Transform vertex
OUT.oPosition = mul(modelViewProj,position);
OUT.color = color;
return OUT;
}
cpp文件main.cpp:
[cpp] view plain copy print ?
- #pragma comment(lib,"cg.lib")
- #pragma comment(lib,"cgGL.lib")
-
- #include <windows.h>
- #include <GL/glut.h>
- #include <CG/cg.h>
- #include <CG/cgGL.h>
- #include <iostream>
-
- using namespace std;
-
-
- static CGcontext context;
- static CGprofile myCgVertexProfile;
- static CGprogram myCgVertexProgram;
- static const char *myProgramName = "CgSample8_VertexTransform",
- *myVertexProgramFileName = "vertex.cg",
- *myVertexProgramName = "main_v";
- bool CgUsed = true;
- static float angle = 0.0;
-
- static void checkForCgError(const char *situation)
- {
- CGerror error;
- const char *string = cgGetLastErrorString(&error);
- if (error != CG_NO_ERROR)
- {
- cout << myProgramName << " "
- <<situation << " "
- << string << endl;
- if( CG_COMPILER_ERROR == error)
- cout << cgGetLastListing(context) << endl;
- exit(1);
- }
- }
-
- void init()
- {
- glClearColor(1.0,1.0,1.0,1.0);
- glShadeModel(GL_SMOOTH);
-
-
- context = cgCreateContext();
-
- myCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
- checkForCgError("selecting vertex profile");
-
- myCgVertexProgram = cgCreateProgramFromFile(
- context,
- CG_SOURCE,
- myVertexProgramFileName,
- myCgVertexProfile,
- myVertexProgramName,
- NULL);
- checkForCgError("Creating vertex Cg program from file");
-
- cgGLLoadProgram(myCgVertexProgram);
- checkForCgError("loading vertex program");
- }
-
- void keyboard(unsigned char key,int x,int y)
- {
- switch(key)
- {
- case 'c':
- CgUsed = !CgUsed;
- glutPostRedisplay();
- break;
- case 27:
- cgDestroyProgram(myCgVertexProgram);
- cgDestroyContext(context);
- exit(0);
- break;
- }
- }
-
- void reshape(int w,int h)
- {
- glViewport(0,0,(GLsizei)w,(GLsizei)h);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(80.0f,(GLfloat)w / (GLfloat)h,1,100);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- gluLookAt(0,0,20,
- 0,0,0,
- 0,1,0);
- }
-
- void idle()
- {
- angle += 1.0;
- if(angle > 360)
- angle -= 360;
-
- glutPostRedisplay();
- }
-
- void display()
- {
- angle += 1.0;
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- if (CgUsed)
- {
- cout << "Cg is been used !" << endl;
-
- cgGLEnableProfile(myCgVertexProfile);
- checkForCgError("enabling vertex profile");
-
- cgGLBindProgram(myCgVertexProgram);
- checkForCgError("binding vertex program");
- }
- else
- cout << "Cg is not used !" << endl;
-
- glColor3f(1.0,0.0,0.0);
- glLoadIdentity();
- glTranslatef(0.0,0.0,-5.0);
- glRotatef(angle,1.0,0.0,0.0);
- glutWireSphere(1.0,30,30);
-
-
-
-
-
-
- cgGLDisableProfile(myCgVertexProfile);
- checkForCgError("disabling vertex profile");
-
- glutSwapBuffers();
- }
-
- int main(int argc,char **argv)
- {
- glutInit(&argc,argv);
- glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
- glutInitWindowPosition(0,0);
- glutInitWindowSize(600,600);
- glutCreateWindow("Cg Test 4");
- init();
- glutDisplayFunc(display);
- glutReshapeFunc(reshape);
- glutKeyboardFunc(keyboard);
- glutIdleFunc(idle);
- glutMainLoop();
-
- return 0;
- }
#pragma comment(lib,"cg.lib")
#pragma comment(lib,"cgGL.lib")
#include <windows.h>
#include <GL/glut.h>
#include <CG/cg.h>
#include <CG/cgGL.h>
#include <iostream>
using namespace std;
//some global variables
static CGcontext context;
static CGprofile myCgVertexProfile;
static CGprogram myCgVertexProgram;
static const char *myProgramName = "CgSample8_VertexTransform",
*myVertexProgramFileName = "vertex.cg",
*myVertexProgramName = "main_v";
bool CgUsed = true;
static float angle = 0.0;
static void checkForCgError(const char *situation)
{
CGerror error;
const char *string = cgGetLastErrorString(&error);
if (error != CG_NO_ERROR)
{
cout << myProgramName << " "
<<situation << " "
<< string << endl;
if( CG_COMPILER_ERROR == error)
cout << cgGetLastListing(context) << endl;
exit(1);
}
}
void init()
{
glClearColor(1.0,1.0,1.0,1.0);
glShadeModel(GL_SMOOTH);
//init Cg
context = cgCreateContext();
myCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
checkForCgError("selecting vertex profile");
myCgVertexProgram = cgCreateProgramFromFile(
context,
CG_SOURCE,
myVertexProgramFileName,
myCgVertexProfile,
myVertexProgramName,
NULL);
checkForCgError("Creating vertex Cg program from file");
cgGLLoadProgram(myCgVertexProgram);
checkForCgError("loading vertex program");
}
void keyboard(unsigned char key,int x,int y)
{
switch(key)
{
case 'c':
CgUsed = !CgUsed;
glutPostRedisplay();
break;
case 27:
cgDestroyProgram(myCgVertexProgram);
cgDestroyContext(context);
exit(0);
break;
}
}
void reshape(int w,int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(80.0f,(GLfloat)w / (GLfloat)h,1,100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,20,
0,0,0,
0,1,0);
}
void idle()
{
angle += 1.0;
if(angle > 360)
angle -= 360;
glutPostRedisplay();
}
void display()
{
angle += 1.0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (CgUsed)//enable Cg
{
cout << "Cg is been used !" << endl;
cgGLEnableProfile(myCgVertexProfile);
checkForCgError("enabling vertex profile");
cgGLBindProgram(myCgVertexProgram);
checkForCgError("binding vertex program");
}
else
cout << "Cg is not used !" << endl;
glColor3f(1.0,0.0,0.0);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
glRotatef(angle,1.0,0.0,0.0);
glutWireSphere(1.0,30,30);
/*glColor3f(0.0,1.0,0.0);
glLoadIdentity();
glTranslatef(-5,0.0,0.0);
glutWireCone(1.5,3.5,20,20);*/
cgGLDisableProfile(myCgVertexProfile);
checkForCgError("disabling vertex profile");
glutSwapBuffers();
}
int main(int argc,char **argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(0,0);
glutInitWindowSize(600,600);
glutCreateWindow("Cg Test 4");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}
运行结果:
![【GPU编程】《The Cg Tutorial》学习之坐标变换(Transformation) ._第2张图片](http://img.e-com-net.com/image/info5/6e2c56203b584110a2ef678a64191e22.jpg)