点精灵(Point Sprite)使用点精灵我们可以通过绘制一个3D点将一个2D纹理图像显示在任意位置上。
点精灵最常见的应用就是微粒系统。我们可以用点来表示在屏幕上移动的大量微粒,来产生一些视觉效果。但是把这些点表示为很小的重叠2D图像就是戏剧性流动着的细丝。
点精灵允许我们通过发送单个3D顶点,渲染一个完美对齐的纹理2D多边形。点精灵所需要的带宽只有为四边形发送四个顶点所用的带宽的四分之一,并且不需要客户端的矩阵逻辑来保持3D四边形和照相机的对齐。

(1)使用点
在客户端我们要做的只是简单绑定一个2D纹理,并且为纹理单元设置恰当的统一值。因为现在点精灵已经是默认的点光栅化模式。一种情况下例外:开启点平滑的时候。
我们不能使用点精灵和抗锯齿点。在片段程序中,有一个内建变量gl_PointCoord,这是一个分量向量,在顶点上对纹理坐标进行插值。

#version 130out vec4 vFragColor;in vec4 vStarColor;uniform sampler2D  starImage;void main(void){ vFragColor = texture(starImage, gl_PointCoord) * vStarColor;}

如上面的片段着色器代码,对于点精灵来说,不需要将纹理坐标作为属性进行传递。
一个点就是一个单独的顶点,那么我们就不能以任何其他方式在点表面上进行插值了。当然如果我们无论如何都要提供一个纹理坐标,或者以自定义的方法进行插值,那么也没什么。

(2)点的大小

两种方式可以设置点的大小。


//第一种方式:
void glPointSize(FLfloat size);

这个函数为锯齿点以及抗锯齿点设置点的直径,以像素为单位。我们也可以在顶点着色器中用程序设置点大小:

//第二种方式
//首先启用点大小模式:
glEnable(GL_PROGRAM_POINT_SIZE);

然后在我们的顶点程序中,可以设置一个内建变量gl_PointSize,这个变量确定了点的最终光栅化大小。这种方式的一种常见用途就是根据点的距离来确定点的大小。当我们使用glPointSize函数设置点的代销的时候,他们不受到透视除法的影响,而是将所有点设置为相同大小。无论他们有多远。
关于点距离变换如下公式:

d为从这个点到观察点的距离,而a,b,c是二次方程的参数。我们可以将他们存储为统一值,并且应用程序来对他们进行更新,或者我们已经想好了一组特定的参数,也可以在顶点着色器中将他们设置为常量。
比如:我们想设置一个常量大小值,那么就将a设置为非0值,而将b,c设置为0。
如果a,c为0,b非0,那么点大小将随着距离变化而线性变化。
如果a,b设置为0,而c设置为非0。那么点大小将随着距离变化而呈平方关系。

(3)飞跃星空代码分析

#pragma comment(lib,"GLTools.lib")#include <GLTools.h>    // OpenGL toolkit
#include <GLFrustum.h>
#include <StopWatch.h>
#include <math.h>
#include <stdlib.h>
#include <GL/glut.h>//定义星星的数量
#define NUM_STARS 10000GLFrustum           viewFrustum;
GLBatch             starsBatch;GLuint  starFieldShader;    // The point sprite shader
GLint   locMVP;             // The location of the ModelViewProjection matrix uniform
GLint   locTimeStamp;       // The location of the time stamp
GLint   locTexture;         // The location of the  texture uniformGLuint  starTexture;        // The star texture texture object// Load a TGA as a 2D Texture. Completely initialize the state
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{GLbyte *pBits;int nWidth, nHeight, nComponents;GLenum eFormat;// Read the texture bitspBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);if (pBits == NULL)return false;glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);glPixelStorei(GL_UNPACK_ALIGNMENT, 1);glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,eFormat, GL_UNSIGNED_BYTE, pBits);free(pBits);if (minFilter == GL_LINEAR_MIPMAP_LINEAR ||minFilter == GL_LINEAR_MIPMAP_NEAREST ||minFilter == GL_NEAREST_MIPMAP_LINEAR ||minFilter == GL_NEAREST_MIPMAP_NEAREST)glGenerateMipmap(GL_TEXTURE_2D);return true;
}// 渲染环境初始化
void SetupRC(void)
{// 背景glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//注意开启点精灵模式glEnable(GL_POINT_SPRITE);//设置四种颜色GLfloat fColors[4][4] = { { 1.0f, 1.0f, 1.0f, 1.0f }, // White{ 0.67f, 0.68f, 0.82f, 1.0f }, // Blue Stars{ 1.0f, 0.5f, 0.5f, 1.0f }, // Reddish{ 1.0f, 0.82f, 0.65f, 1.0f } }; // Orange// 随机位置,随机颜色starsBatch.Begin(GL_POINTS, NUM_STARS);//直接添加10000个点for (int i = 0; i < NUM_STARS; i++){int iColor = 0;     // 初始化星星颜色为0// 五分之一为蓝色if (rand() % 5 == 1)iColor = 1;// 五十分之一为红色if (rand() % 50 == 1)iColor = 2;// 一百分之一为橙色if (rand() % 100 == 1)iColor = 3;//将颜色添加到batch当中starsBatch.Color4fv(fColors[iColor]);M3DVector3f vPosition;//上下600像素随机值vPosition[0] = float(3000 - (rand() % 6000)) * 0.1f;vPosition[1] = float(3000 - (rand() % 6000)) * 0.1f;vPosition[2] = -float(rand() % 1000) - 1.0f;  // -1 to -1000.0fstarsBatch.Vertex3fv(vPosition);}starsBatch.End();//调用渲染器代码以及传递值如下:starFieldShader = gltLoadShaderPairWithAttributes("SpaceFlight.vp", "SpaceFlight.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex",GLT_ATTRIBUTE_COLOR, "vColor");//设置其中的统一值locMVP = glGetUniformLocation(starFieldShader, "mvpMatrix");locTexture = glGetUniformLocation(starFieldShader, "starImage");locTimeStamp = glGetUniformLocation(starFieldShader, "timeStamp");//绑定纹理注意是2DglGenTextures(1, &starTexture);glBindTexture(GL_TEXTURE_2D, starTexture);//并且加载tga图像LoadTGATexture("Star.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
}// Cleanup
void ShutdownRC(void)
{glDeleteTextures(1, &starTexture);
}// Called to draw scene
void RenderScene(void)
{static CStopWatch timer;// 清除视窗以及深度缓冲区。glClear(GL_COLOR_BUFFER_BIT);// 开启混合模式glEnable(GL_BLEND);glBlendFunc(GL_ONE, GL_ONE);//定义混合的方式// 让顶点程序决定点的大小glEnable(GL_PROGRAM_POINT_SIZE);// 开启渲染器程序,并且为统一值赋值glUseProgram(starFieldShader);glUniformMatrix4fv(locMVP, 1, GL_FALSE, viewFrustum.GetProjectionMatrix());glUniform1i(locTexture, 0);// 使用定时器来调节点的距离float fTime = timer.GetElapsedSeconds() * 10.0f;//得到对应的余数fTime = fmod(fTime, 999.0f);glUniform1f(locTimeStamp, fTime);//画出星星starsBatch.Draw();glutSwapBuffers();glutPostRedisplay();
}void ChangeSize(int w, int h)
{// Prevent a divide by zeroif (h == 0)h = 1;// Set Viewport to window dimensionsglViewport(0, 0, w, h);//设置透视模式viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 1000.0f);
}///
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{gltSetWorkingDirectory(argv[0]);glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);glutInitWindowSize(800, 600);glutCreateWindow("Spaced Out");glutReshapeFunc(ChangeSize);glutDisplayFunc(RenderScene);GLenum err = glewInit();if (GLEW_OK != err) {fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));return 1;}SetupRC();glutMainLoop();ShutdownRC();return 0;
}

关于程序实现的点渲染器代码:

#version 130// 输入每个点的坐标以及颜色
in vec4 vVertex;
in vec4 vColor;uniform mat4   mvpMatrix;
uniform float  timeStamp;out vec4 vStarColor;void main(void) {vec4 vNewVertex = vVertex;vStarColor = vColor;// 跟随时间而不断移动vNewVertex.z += timeStamp;//顶点的z位置通过时间戳统一值进行偏移,星星向我们移动的动画效果就是这么实现的。我们需要检查位置
//当到达临近剪切面时,只要将他们的位置进行循环回到远端剪切面即可。我们使用一个平方根倒数,
//函数来使得星星在靠近我们的过程中越来越大,并且用变量设置最终的大小。// 如果越界那么更新其位置if(vNewVertex.z > -1.0)vNewVertex.z -= 999.0;gl_PointSize = 30.0 + (vNewVertex.z / sqrt(-vNewVertex.z));//如果点大小太小,那么需要淡入,由无到有进行淡入if(gl_PointSize < 4.0)vStarColor = smoothstep(0.0, 4.0, gl_PointSize) * vStarColor;// 更新几何变换gl_Position = mvpMatrix * vNewVertex;}

(4)点参数
通过glPointParameter函数,我们可以对点精灵的几个特征进行微调。应用到一个点精灵上的纹理的原点(0,0)的两个可能位置。
将GL_POINT_SPRITE_COORD_ORIGIN参数设置为GL_LOWER_LEFT, 可以将纹理坐标系的原点放置在点的左下角。
glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);注意点精灵的默认方向为GL_UPPER_LEFT。
另外一个和纹理无关的点参数可以用来设置alpha值,使得点可以通过将alpha与到观察点的距离进行混合而逐渐消失。

(5)异形点
除了gl_PointCoord为纹理坐标应用纹理之外,我们还可以使用点精灵完成一些其他工作。gl_FragCoord就是一个内建变量。
在任何其他图元进行渲染时, gl_FragCoord会包含当前片段的屏幕空间坐标。这样,这个坐标的x,y分量在这个点区域的不同位置也不相同。z和w分量都是常量,因为这个点是作为一个平面进行渲染的。这个平面和近端面和远端面平行。
同时我们可以使用gl_PointCoord来完成很多工作,而不仅仅是纹理坐标。
我们可以在片段着色器当中使用discard关键字来丢弃位于我们想要点形状范围之外的片段,从而创建出非正方形的点。
下面给出两个示例程序:

//绘制一个圆形
vec2 p=gl_PointCoord*2.0-vec2(1.0);
if(dot(p,p)>1.0)
discard;//生成花朵形状
vec2 temp=gl_PointCoord*2-vec2(1);
if(dot(temp,temp)>sin(atan(temp.y,temp.x)*5))
discard;

(6)点的旋转
OPENGL当中的点是作为按轴对其的正方形而进行渲染的,对点精灵进行旋转必须通过修改用于读取点精灵纹理的纹理坐标来完成的。要完成这项工作,我们只需要在片段着色器当中创建一个2D旋转矩阵,并且用它乘以一个gl_PointCoord使他绕着z轴进行旋转。旋转的角度可以从顶点着色器或者几何着色器中作为一个插值变量传递到片段着色器。变量的值可以在顶点着色器或几何着色器当中一次计算,也可以通过一个顶点属性提供。

#version 330uniform sampler2D sprite_texture;in float angle;out vec4 color;void main(void)
{
const float sin_theta=sin(angle);
const floay cos_theta=cos(angle);
const mat2 rotation_matrix=mat2(cos_theta, sin_theta,-sin_theta, cos_theta);
const vec2 pt=gl_PointCoord-vec2(0.5);
color=texture(sprite_texture, rotation_matrix*pt + vec(0.5));}

注意,这个实例允许我们创建旋转的点精灵。不过,angle的值当然不能在点精灵中的片段之间进行改变。这就是说,对于点中的每个片段来说,旋转矩阵也是一个常量。这样,比起为每个片段分别计算旋转矩阵,在顶点着色器当中进行旋转矩阵运算,然后将它作为一个mat2变量传递给片段着色器的效率要高得多。

这里有一个更新过的顶点着色器和片段着色器,允许我们绘制旋转的点精灵。

#version 330uniform matrix mvp;in vec4 position;
in float angle;out mat2 rotation_matrix;void main(void)
{
const float sin_theta = sin(angle);
const float cos_theta=cos(angle);
const mat2 rotation_matrix=mat2(cos_theta, sin_theta,-sin_theta, cos_theta);
gl_Position= mvp* position;
}
#version 330uniform sampler2D sprite_texture;in mat2 rotation_matrix;out vec4 color;void main(void)
{const vec2 pt=gl_PointCoord-vec2(0.5);
color=texture(sprite_texture, rotation_matrix*pt + vec(0.5));}

如上面的实例所示,把大量的计算转移到顶点着色器当中。

渲染世界的OPENGL15纹理进阶-点精灵相关推荐

  1. Metal 框架之渲染到多个纹理切片

    概述 使用图层选择为顶点着色器中的每个图元选择目标切片,可以将图元渲染到纹理数组.立方体纹理或 3D 纹理的多个层(切片)中.层是单个 1D.2D 或 3D 像素块,由目标纹理中的切片和 mipmap ...

  2. 渲染世界的OPENGL12 一些有趣的纹理着色器

    从着色器访问纹理贴图是非常简单的.纹理坐标将会作为属性传递到我们的顶点着色器,在片段着色器当中,这些属性通常是在顶点之间进行平滑插值的.片段着色器使用这些差值纹理坐标来对纹理进行采样. (1)只处理纹 ...

  3. coco2dx精灵和背景遮挡_Cocos2d-x精灵的性能优化——使用纹理图集和精灵帧缓存...

    使用纹理图集 纹理图集(Texture)也称为精灵表(Sprite Sheet) 使用纹理图集的优点: 1.减少文件读取次数,读取一张图片比读取一推小文件要快 2.减少OpenGL ES绘制调用并且加 ...

  4. android OpenGL ES实现渲染到透明的纹理 render to transparent texture

    PC上OpenGL渲染到纹理,很容易得到透明背景,但是在android上OpenGL ES渲染出来是黑色背景,对于这个问题,想了两个解决办法. 1> 让android的OpenGL ES环境支持 ...

  5. Arnold 渲染设置 - Main - Textures 纹理

    Mip mapping (Mip映射)它采用一个原始的高分辨率的纹理图像,在被应用于表面之前,会缩放和过滤成多个分辨率,如果近距离观察,纹理可以显示完整的分辨率和细节,而当物体看起来更小或者更远时,可 ...

  6. 【CSS进阶】精灵图、字体图标、用户界面样式、常见布局技巧、初始化、CSS三角

    该系列文章是博主学习前端入门课程的笔记,同时也为了方便查阅,有任何问题都欢迎在评论区提出.本文主要介绍精灵图.字体图标.CSS三角.用户界面样式.vertical-align.常见布局技巧.初始化 思 ...

  7. 教学|ZBrush纹理绘制之,如何渲染逼真的皮肤纹理

    创建纹理的过程非常简单,这也是一门技术,可应用于大多数皮肤类型,甚至是拥有不同肤色的生物. 以下是没有多边形着色的模型,左上角是刚开始绘制的版本,在后面的步骤中会用到笔刷.笔触和通道(alpha). ...

  8. css进阶:精灵图的使用、实现用精灵图拼出名字

    目录 1.精灵图的用途 2. 精灵图(sprites)的使用 2.1 原理 2.2 总结 3. 案例:用精灵图拼出名字 3.1 效果图 3.2 代码 1.精灵图的用途 为了有效地减少服务器接收和请求的 ...

  9. XCTF 攻防世界 MISC杂项 高手进阶区

    文章目录 hit-the-core(找规律) 2017_Dating_in_Singapore(脑洞) can_has_stdio?(Brainfuck) 打野(zsteg) a_good_idea( ...

最新文章

  1. MVC、MVP、MVVM
  2. 技术 | Bengio终结Theano不是偶然,其性能早在Keras支持的四大框架中垫底
  3. 依然在那条路上奋斗着
  4. docker 集群中文件挂载的问题
  5. swoole使用 常用案例
  6. 导线坐标计算软件_8套超全建筑工程测量计算表,输入参数得到精确结果,从此不加班...
  7. 处理大并发之四 libevent demo详细分析(对比epoll)
  8. 微服务架构,如何做分布式,通用缓存机制?
  9. 如何启用计算机的远程服务,远程桌面服务,教您怎么打开远程桌面服务
  10. java 面试代码_java代码编写及面试题
  11. Django:DjangoProject项目结构简介
  12. 第一篇:FC-SAN存储技术
  13. table固定表头、固定列
  14. selenium 12306登录滑块验证码
  15. 数据库实验三 存储过程与触发器
  16. gmap实现地图的旋转
  17. 利用特性、泛型、反射生成sql操作语句(待修改
  18. 胃肠道微生物与癌症有关
  19. python结束子进程_如何清除python中的子进程
  20. 技术展示:综合布线系统的设计分析

热门文章

  1. Mac、iPhone 和 iPad 备份加密教程
  2. sql server 2008 r2 产品密钥
  3. 风格迁移1-05:Liquid Warping GAN(Impersonator)-白话给你讲论文-翻译无死角(2)
  4. CTeX下的WinEdt和GSview相关的破解和自动补足
  5. YUV444,YUV422P,YUVY,YUYV,UYVY,NV21,NV12
  6. Android是美图软件吗,Android摄影软件推荐:美图秀秀与魔图精灵等
  7. IDEA插件系列(64):Document Assistant插件——SpringMVC文档助手
  8. HQL怎么用身份证计算年龄
  9. 空军一号html,耐克AF1所有款式介绍 NIKE空军一号款式一览
  10. Java蓝桥杯 算法训练 复数归一化