以文本方式查看主题 - 中文XML论坛 - 专业的XML技术讨论区 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 47-lesson 48【本教程全部传完】 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=54730) |
-- 作者:一分之千 -- 发布时间:11/1/2007 11:50:00 AM -- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 47-lesson 48【本教程全部传完】 nVidio的面向GPU的C语言,如果你相信它就好好学学吧,同样这里也只是个入门。记住,类似的语言还有微软的HLSL,OpenGL的GLSL,ATI的shaderMonker。不要选错哦:) 这个教程是基于最新的NeHeGL的基本代码,为了获得更多的信息,你可以访问nVidia的官方网站(developer.nvidia.com),它会给你一个完整的答案。 注意:这个教程不是叫你如何去写一个完整的Cg脚本,而是教你在OpenGL中载入并运行脚本。 开始: 下一步,包含编译需要的头文件和库文件。 Cg介绍 好了,现在我们创建一个空白的文件吧(保存为wave.cg),接着我们创建一个数据结构,它被我们得脚本使用。下面的代码被加入到wave.cg文件中。 struct appdata { float4 position : POSITION; float4 color : COLOR0; float3 wave : COLOR1;}; struct vfconn{ float4 HPos : POSITION; float4 Col0 : COLOR0;}; vfconn main(appdata IN, uniform float4x4 ModelViewProj) // 计算顶点y的坐标 // 保存到输出数据中 // 不改变输入的颜色 return OUT; 下面我们到了程序中,首先包含使用cg需要的头文件,和库文件 #include <cg\cg.h> #include <cg\cggl.h> #define SIZE 64 // 定义网格的大小bool cg_enable = TRUE, sp; // 开关Cg程序GLfloat mesh[SIZE][SIZE][3]; // 保存我们的网格GLfloat wave_movement = 0.0f; // 记录波动的移动 CGcontext cgContext; // 用来保存cg脚本 CGprogram cgProgram; // 我们得顶点脚本 CGprofile cgVertexProfile; // 被顶点脚本使用 CGparameter position, color, modelViewMatrix, wave; // 脚本中需要的参数 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 设置Cg cgContext = cgCreateContext(); // 创建一个Cg容器 cgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); // 配置在OpenGL中使用顶点缓存 cgGLSetOptimalOptions(cgVertexProfile); // 启用配置文件 // 从文件中载入Cg程序 cgProgram = cgCreateProgramFromFile(cgContext, CG_SOURCE, "CG/Wave.cg", cgVertexProfile, "main", 0); // 载入脚本 cgGLLoadProgram(cgProgram); // 把数据变量地址发送给Cg程序 position = cgGetNamedParameter(cgProgram, "IN.position"); color = cgGetNamedParameter(cgProgram, "IN.color"); wave = cgGetNamedParameter(cgProgram, "IN.wave"); modelViewMatrix = cgGetNamedParameter(cgProgram, "ModelViewProj"); cgDestroyContext(cgContext); if (g_keys->keyDown [' '] && !sp) { sp=TRUE; cg_enable=!cg_enable; } gluLookAt(0.0f, 25.0f, -45.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0); 结下来如果使用cg程序,则把顶点的颜色设置为绿色 // 如果使用Cg程序 if (cg_enable) { // 使用顶点脚本配置文件 cgGLEnableProfile(cgVertexProfile); // 帮定到当前的顶点脚本 cgGLBindProgram(cgProgram); // 设置绘制颜色 cgGLSetParameter4f(color, 0.5f, 1.0f, 0.5f, 1.0f); } // 开始绘制我们的网格 for (int x = 0; x < SIZE - 1; x++) { glBegin(GL_TRIANGLE_STRIP); for (int z = 0; z < SIZE - 1; z++) { // 设置Wave参数 cgGLSetParameter3f(wave, wave_movement, 1.0f, 1.0f); //设置输入的顶点 glVertex3f(mesh[x][z][0], mesh[x][z][1], mesh[x][z][2]); glVertex3f(mesh[x+1][z][0], mesh[x+1][z][1], mesh[x+1][z][2]); wave_movement += 0.00001f; if (wave_movement > TWO_PI) wave_movement = 0.0f; } //经过Cg程序处理,进行绘制 glEnd(); } if (cg_enable) cgGLDisableProfile(cgVertexProfile); // 禁用顶点脚本配置文件 |
-- 作者:一分之千 -- 发布时间:11/1/2007 11:51:00 AM -- Lesson: 47 Using vertex and fragment (or pixel) shaders to do some rendering dirty work can have numerous benefits. The most obvious is the movement of some of the graphics related CPU load off the CPU and onto the GPU. Cg provides a (reasonably) simple language for writing very powerful shaders. This tutorial has multiple aims. The first is to present a simple vertex shader that actually does something, without introducing unnecessary lighting etc… The second is to provide the basic mechanism for running the vertex shader with visible results using OpenGL. As such, it is aimed at the beginner interested in Cg who has a little experience in OpenGL. This tutorial is based on the Latest NeHeGL Basecode. For more information on Cg check out nVidia’s website (developer.nvidia.com) and www.cgshaders.org for some cool shaders. NOTE: This tutorial is not intended to teach you everything you need to know about writing vertex shaders using Cg. It is intended to teach you how to successfully load and run vertex shaders within OpenGL. The first step (if it hasn’t been done already) is to download the Cg Compiler from nVidia. It is important that you download version 1.1, as nVidia appear to have made changes between version 1.0 and 1.1 (different variable naming, replaced functions, etc…), and code compiled for one may not necessarily work with the other. The next step is to setup the header files and library files for Cg to a place where Visual Studio can find them. Because I am inherently distrustful of installers working the way they are supposed to, I copy the library files... From: C:\Program Files\NVIDIA Corporation\Cg\libTo: C:\Program Files\Microsoft Visual Studio\VC98\Lib From: C:\Program Files\NVIDIA Corporation\Cg\includeTo: C:\Program Files\Microsoft Visual Studio\VC98\Include The information regarding Cg contained in this tutorial was obtained mostly from the Cg Toolkit User’s Manual. There are a few important points that you need to remember when dealing with vertex (and later fragment) programs. The first thing to remember is that a vertex program will execute in its entirety on EVERY vertex. The only way to run the vertex program on selected vertices is to either load/unload the vertex program for each individual vertex, or to batch vertices into a stream that are affected by the vertex program, and a stream that isn’t. The output of a vertex program is passed to a fragment shader, regardless of whether you have implemented and activated a fragment shader. Finally, remember that a vertex program is executed on the vertices before primitive assembly, while a fragment program is executed after rasterization. On with the tutorial. First, we need to create a blank file (save as “wave.cg”). We then create a structure to contain the variables and information that we want available to our shader. This code is added to the wave.cg file. struct appdata { float4 position : POSITION; float4 color : COLOR0; float3 wave : COLOR1;}; struct vfconn{ float4 HPos : POSITION; float4 Col0 : COLOR0;}; vfconn main(appdata IN, uniform float4x4 ModelViewProj){ vfconn OUT; // Variable To Handle Our Output From The Vertex // Shader (Goes To A Fragment Shader If Available We declare a variable to hold our modified values from the vertex shader. These values are returned at the end of the function, and are passed to the fragment shader (if it exists). We now need to perform our modifications to the vertex data. . // Change The Y Position Of The Vertex Based On Sine Waves IN.position.y = ( sin(IN.wave.x + (IN.position.z / 4.0) ) + sin(IN.wave.x + (IN.position.x / 5.0) ) ) * 2.5f; We now perform the required operations to determine the values to output to the fragment program. // Transform The Vertex Position Into Homogenous Clip-Space (Required) OUT.HPos = mul(ModelViewProj, IN.position); return OUT; OpenGL tutorial: The main sequence of steps for dealing with our Cg shader is to generate our mesh, load up and compile our Cg program and then run this program on each vertex as it is being drawn. First we must get some of the necessary setup details out of the way. We need to include the necessary header files to run Cg shaders with OpenGL. After our other #include statements, we need to include the Cg and CgGL headers. #include <cg\cg.h> // NEW: Cg Header#include <cg\cggl.h> // NEW: Cg OpenGL Specific Header #pragma comment( lib, "cg.lib" ) // Search For Cg.lib While Linking#pragma comment( lib, "cggl.lib" ) // Search For CgGL.lib While Linking #define SIZE 64 // Defines The Size Of The X/Z Axis Of The Meshbool cg_enable = TRUE, sp; // Toggle Cg Program On / Off, Space Pressed?GLfloat mesh[SIZE][SIZE][3]; // Our Static MeshGLfloat wave_movement = 0.0f; // Our Variable To Move The Waves Across The Mesh CGcontext cgContext; // A Context To Hold Our Cg Program(s) CGprogram cgProgram; // Our Cg Vertex Program CGprofile cgVertexProfile; // The Profile To Use For Our Vertex Shader CGparameter position, color, modelViewMatrix, wave; // The Parameters Needed For Our Shader In our Initialize function, before we call “return TRUE;”, we need to add our custom code. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Draw Our Mesh In Wireframe Mode // Setup Cg cgContext = cgCreateContext(); // Create A New Context For Our Cg Program(s) cgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); // Get The Latest GL Vertex Profile cgGLSetOptimalOptions(cgVertexProfile); // Set The Current Profile // Load And Compile The Vertex Shader From File cgProgram = cgCreateProgramFromFile(cgContext, CG_SOURCE, "CG/Wave.cg", cgVertexProfile, "main", 0); // Show A Message Box Explaining What Went Wrong We’re almost finished our initialization. // Load The Program cgGLLoadProgram(cgProgram); // Get Handles To Each Of Our Parameters So That // We Can Change Them At Will Within Our Code position = cgGetNamedParameter(cgProgram, "IN.position"); color = cgGetNamedParameter(cgProgram, "IN.color"); wave = cgGetNamedParameter(cgProgram, "IN.wave"); modelViewMatrix = cgGetNamedParameter(cgProgram, "ModelViewProj"); We’ve finally finished with the initialization of our Cg program, so now we’ll quickly take care of cleaning up after ourselves, and then it’s on to the fun of drawing. In the function Deinitialize, we need clean up our Cg program(s). cgDestroyContext(cgContext); // Destroy Our Cg Context And All Programs Contained Within It if (g_keys->keyDown [' '] && !sp) { sp=TRUE; cg_enable=!cg_enable; } if (!g_keys->keyDown [' ']) sp=FALSE; // Position The Camera To Look At Our Mesh From A Distance gluLookAt(0.0f, 25.0f, -45.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0); // Set The Modelview Matrix Of Our Shader To Our OpenGL Modelview Matrix cgGLSetStateMatrixParameter(modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); if (cg_enable) { cgGLEnableProfile(cgVertexProfile); // Enable Our Vertex Shader Profile // Set The Drawing Color To Light Green (Can Be Changed By Shader, Etc...) cgGLSetParameter4f(color, 0.5f, 1.0f, 0.5f, 1.0f); } We’re now ready to render our mesh! // Start Drawing Our Mesh for (int x = 0; x < SIZE - 1; x++) { // Draw A Triangle Strip For Each Column Of Our Mesh glBegin(GL_TRIANGLE_STRIP); for (int z = 0; z < SIZE - 1; z++) { // Set The Wave Parameter Of Our Shader To The Incremented Wave Value From Our Main Program cgGLSetParameter3f(wave, wave_movement, 1.0f, 1.0f); glVertex3f(mesh[x][z][0], mesh[x][z][1], mesh[x][z][2]); // Draw Vertex glVertex3f(mesh[x+1][z][0], mesh[x+1][z][1], mesh[x+1][z][2]); // Draw Vertex wave_movement += 0.00001f; // Increment Our Wave Movement if (wave_movement > TWO_PI) // Prevent Crashing wave_movement = 0.0f; } glEnd(); } We then pass the vertices we are currently drawing to our GPU, while the GPU will handle automatically running the our vertex program on each vertex. We slowly increment our wave_movement variable so as to get slow and smooth movement. If the value of wave_movement gets to high, we reset it back to 0 to prevent crashing. TWO_PI is defined at the top of the program. if (cg_enable) cgGLDisableProfile(cgVertexProfile); // Disable Our Vertex Profile |
-- 作者:一分之千 -- 发布时间:11/1/2007 11:52:00 AM -- 第四十八课
使用鼠标旋转物体,很简单也有很多实现方法,这里我们教会你模拟轨迹球来实现它. 我的实现是基于Bretton Wade’s,它是基于Ken Shoemake’s 实现的,最初的版本,你可以从游戏编程指南这本图上找到。但我还是修正了一些错误,并优化了它。 轨迹球实现的内容就是把二维的鼠标点映射到三维的轨迹球,并基于它完成旋转变化。 为了完成这个设想,首先我们把鼠标坐标映射到[-1,1]之间,它很简单: MousePt.X = ((MousePt.X / ((Width -1) / 2)) -1);MousePt.Y = -((MousePt.Y / ((Height -1) / 2))-1); 下面我们从构造函数开始,完整的讲解这个类: ArcBall_t::ArcBall_t(GLfloat NewWidth, GLfloat NewHeight) void ArcBall_t::click(const Point2fT* NewPt) void ArcBall_t::drag(const Point2fT* NewPt, Quat4fT* NewRot) void ArcBall_t::setBounds(GLfloat NewWidth, GLfloat NewHeight) Matrix4fT Transform = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; Matrix3fT ThisRot = { 1.0f, 0.0f, 0.0f, ArcBallT ArcBall(640.0f, 480.0f); 为了更新鼠标的移动范围,我们在函数ReshapeGL中加入下面一行: void ReshapeGL (int width, int height){ . . . ArcBall.setBounds((GLfloat)width, (GLfloat)height); // 更新鼠标的移动范围} case WM_LBUTTONUP: isClicked = false; break; if (isRClicked) // 如果右键按下,这重置所有的变量{ Matrix3fSetIdentity(&LastRot); ArcBall.drag(&MousePt, &ThisQuat); // 更新轨迹球的变量 glPushMatrix(); // 保存当前的矩阵 glMultMatrixf(Transform.M); // 应用我们的变换矩阵 glPopMatrix(); // 弹出保存的矩阵 |
-- 作者:一分之千 -- 发布时间:11/1/2007 11:53:00 AM -- Lesson: 48 ArcBall Rotation Control, Revisited By Terence J. Grant (tjgrant@tatewake.com) Wouldn’t it be great to rotate your model at will, just by using the mouse? With an ArcBall you can do just that. In this document, I’ll touch on my implementation, and considerations for adding it to your own projects. My implementation of the ArcBall class is based on Bretton Wade’s, which is based on Ken Shoemake’s from the Graphic Gems series of books. However, I did a little bug fixing and optimization for our purposes. The ArcBall works by mapping click coordinates in a window directly into the ArcBall’s sphere coordinates, as if it were directly in front of you. To accomplish this, first we simply scale down the mouse coordinates from the range of [0...width), [0...height) to [-1...1], [1...-1] – (Keep in mind that we flip the sign of Y so that we get the correct results in OpenGL.) And this essentially looks like: MousePt.X = ((MousePt.X / ((Width – 1) / 2)) – 1);MousePt.Y = -((MousePt.Y / ((Height – 1) / 2)) – 1); Once we have both vectors, we can then calculate a vector perpendicular to the start and end vectors with an angle, which turns out to be a quaternion. With this in hand we have enough information to generate a rotation matrix from, and we’re home free. The ArcBall is instantiated using the following constructor. NewWidth and NewHeight are essentially the width and height of the window. ArcBall_t::ArcBall_t(GLfloat NewWidth, GLfloat NewHeight) void ArcBall_t::click(const Point2fT* NewPt) void ArcBall_t::drag(const Point2fT* NewPt, Quat4fT* NewRot) void ArcBall_t::setBounds(GLfloat NewWidth, GLfloat NewHeight) // Final TransformMatrix4fT Transform = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; Matrix3fT ThisRot = { 1.0f, 0.0f, 0.0f, // This Rotation ArcBallT ArcBall(640.0f, 480.0f); // ArcBall Instance This is where LastRot and ThisRot come into play. LastRot can be defined as “all rotations up till now”, whereas ThisRot can be defined by “the current rotation.” Every time a drag is started, ThisRot is modified by the original rotation. It is then updated to the product of itself * LastRot. (Then the final transformation is also updated.) Once a drag is stopped, LastRot is then assigned the value of ThisRot. If we didn’t accumulate the rotations ourselves, the model would appear to snap to origin each time that we clicked. For instance if we rotate around the X-axis 90 degrees, then 45 degrees, we would want to see 135 degrees of rotation, not just the last 45. For the rest of the variables (except for isDragged), all you need to do is update them at the proper times based on your system. ArcBall needs its bounds reset whenever your window size changes. MousePt gets updated whenever your mouse moves, or just when the mouse button is down. isClicked / isRClicked whenever the left/right mouse button is clicked, respectively. isClicked is used to determine clicks and drags. We’ll use isRClicked to reset all rotations to identity. The additional system update code under NeHeGL/Windows looks something like this: void ReshapeGL (int width, int height){ . . . ArcBall.setBounds((GLfloat)width, (GLfloat)height); // Update Mouse Bounds For ArcBall} case WM_LBUTTONUP: isClicked = false; break; if (isRClicked) // If Right Mouse Clicked, Reset All Rotations{ // Reset Rotation Matrix3fSetIdentity(&LastRot); // Reset Rotation if (!isDragging) // Not Dragging ArcBall.drag(&MousePt, &ThisQuat); // Update End Vector And Get Rotation As Quaternion glPushMatrix(); // Prepare Dynamic Transform glMultMatrixf(Transform.M); // Apply Dynamic Transform glPopMatrix(); // Unapply Dynamic Transform Terence J. Grant |
-- 作者:长风万里 -- 发布时间:11/1/2007 7:06:00 PM -- 谢谢你! 没了吗? |
-- 作者:emc2010 -- 发布时间:12/16/2011 4:21:00 PM -- 这些都学会 差不多就入门了 谢谢楼主了!! |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
187.500ms |