当前位置: 首页 > news >正文

国外那些网站是做菠菜的如何判断网站做没做404

国外那些网站是做菠菜的,如何判断网站做没做404,找培训机构的平台,陕西网络推广介绍在本篇#xff0c;我们将开启一个新的项目#xff0c;探索粒子的世界。粒子是一种基本的图形元素#xff0c;它们通常被表示为一组点。通过巧妙地组合一些基础的物理效果#xff0c;我们能够创造出许多令人惊叹的视觉效果。想象一下#xff0c;我们可以模拟一个水滴从喷泉…在本篇我们将开启一个新的项目探索粒子的世界。粒子是一种基本的图形元素它们通常被表示为一组点。通过巧妙地组合一些基础的物理效果我们能够创造出许多令人惊叹的视觉效果。想象一下我们可以模拟一个水滴从喷泉中喷出然后优雅地落回地面的场景。同样我们也能模拟出逼真的下雨效果或者制作出爆炸和烟花的动画。粒子系统的数学原理相对简单这使得它们很容易被集成到任何三维场景中。 在本章我们将逐步构建一个粒子系统。首先我们会介绍创建粒子系统所需的基本要素。接下来我们将添加喷泉效果让粒子喷射到空中。此外我们还会探讨如何通过技术手段如混合和点精灵来提升粒子的视觉效果使它们看起来更加好看。 创建着色器 作为开始我们将构建一个基础的粒子系统模拟一个喷泉。这个喷泉可以想象成在灯光下喷发的泉水或者像烟花表演中的喷泉一样。为了实现这个效果我们需要处理一些技术细节。 首先我们需要找到一种方式来在内存中表示所有的粒子。虽然可以使用Java对象数组但在运行时创建和删除大量对象可能会导致资源消耗过大并且没有简单的方法将数据传递给OpenGL。因此我们选择将所有粒子数据嵌入到一个固定大小的数组中。添加粒子时我们只需增加粒子计数将数据写入粒子数组并把变化的内容复制到本地缓冲区。当空间不足时可以通过在数组开头重新开始来回收空间。 接下来我们需要一种方法来绘制每个粒子。我们将每个粒子表示为一个顶点并绘制一组点每个点都有其独特的位置和颜色。 最后我们需要一种方法来更新这些粒子。将这些逻辑放入着色器程序中可以让GPU分担一部分更新工作。对于每个粒子我们需要存储一个方向向量和一个创建时间。利用创建时间我们可以计算出粒子自创建以来经过的时间然后使用这个时间、方向向量和位置来推算出粒子当前的位置。我们将使用一个浮点数来存储时间并以0.0表示粒子系统开始运行的时间。 有了这些基本需求我们可以为着色器程序制定一套初始规范。首先我们需要定义一个uniform变量用于投影矩阵以及一个用于当前时间的uniform变量以便着色器计算出每个粒子自创建以来经过的时间。我们还需要定义四个与粒子属性相对应的属性位置、颜色、方向向量和创建时间。 1.编写顶点着色器 让我们开始给着色器添加代码。继续并在“/res/raw/”文件夹内创建一个名为“particle_vertex_shader.glsl”的新顶点着色器。首先以如下定义作为开始 uniform mat4 u_Matrix; uniform float u_Time;attribute vec3 a_Position; attribute vec3 a_Color; attribute vec3 a_DirectionVector; attribute float a_ParticleStartTime;varying vec3 v_Color; varying float v_ElapsedTime;void main(){v_Color a_Color;v_ElapsedTime u_Time - a_ParticleStartTime;vec3 currentPosition a_Position (a_DirectionVector * v_ElapsedTime);gl_Position u_Matrix * vec4(currentPosition,1.0);gl_PointSize 10.0; }这些定义满足了我们的粒子着色器的需求。我们在片段着色器中也需要使用颜色和运行时间因此我们也为这两个变量创建了两个varying。 在main函数中我们首先把颜色发送给片段着色器接着计算粒子从被创建之后运行了多少时间并且把那个时间也发送给片段着色器。为了计算粒子的当前位置我们把方向向量与运行时间相乘并与a_Position相加。运行时间越长粒子走得越远。 要完成这个着色器代码我们把粒子用那个矩阵进行投影而且因为我们把粒子渲染为一个点所以把点的大小设成了10个像素。 当我们做数学运算时要确保不会意外地把w分量弄混乱这是很重要的。因此我们将用3分量向量表示位置和方向只有需要把它与u_Matrix相乘时才把它转换为完全的4分量向量。这确保上面的数学运算只影响x、y和z分量。 2.编写片段着色器 现在我们可以继续并添加片段着色器了。在与顶点着色器相同的地方创建一个被称为“particle_fragment_shader.glsl”的新文件并加入如下代码 precision mediump float; varying vec3 v_Color; varying float v_ElapsedTime;void main(){gl_FragColor vec4(v_Color / v_ElapsedTime,1.0); }通过把颜色除以运行时间这个着色器会使年轻的粒子明亮而使年老的粒子暗淡。如果发生除以0的情况怎么办根据规范这会导致一个不明确的结果但不会导致着色器程序终止。要一个更加可预测的结果你可以总是给分母加上一个很小的数。 3.用一个类封装着色器 着色器代码完成了我们现在可以用一个类封装着色器它使用我们在本书第一部分所使用的模式。让我们首先给 ShaderProgram加入一些新的常量 protected val U_TIME u_Timeprotected val A_DIRECTION_VECTOR a_DirectionVectorprotected val A_PARTICLE_START_TIME a_ParticleStartTime这些新的常量被定义后我们可以继续加入一个名为“ParticleShaderProgram”的新类它继承自ShaderProgram并以如下代码作为这个类的开始 private var uMatrixLocation 0private var uTimeLocation 0var aPositionLocation 0var aColorLocation 0var aDirectionVectorLocation 0var aParticleStartTimeLocation 0 接着继续完成这个类的定义 constructor(context: Context):super(context, R.raw.particle_vertex_shader,R.raw.particle_fragment_shader1){uMatrixLocation findUniformLocationByName(U_MATRIX)uTimeLocation findUniformLocationByName(U_TIME)aPositionLocation findAttribLocationByName(A_POSITION)aColorLocation findAttribLocationByName(A_COLOR)aDirectionVectorLocation findAttribLocationByName(A_DIRECTION_VECTOR)aParticleStartTimeLocation findAttribLocationByName(A_PARTICLE_START_TIME)uTextureUnitLocation findUniformLocationByName(U_TEXTURE_UNIT)}fun setUniforms(matrix:FloatArray,elapsedTime:Float){GLES20.glUniformMatrix4fv(uMatrixLocation,1,false,matrix,0)GLES20.glUniform1f(uTimeLocation,elapsedTime)}封装模式与前面篇章的一致这里就不再过多赘述。 添加粒子系统 我们现在可以开始创建粒子系统了。让我们创建一个名为“ParticleSystem”的新类这个类以如下代码开始 private val POSITION_COMPONENT_COUNT 3private val COLOR_COMPONENT_COUNT 3private val VECTOR_COMPONENT_COUNT 3private val PARTICLE_START_TIME_COMPONENT_COUNT 1private val TOTAL_COMPONENT_COUNT POSITION_COMPONENT_COUNT COLOR_COMPONENT_COUNT VECTOR_COMPONENT_COUNT PARTICLE_START_TIME_COMPONENT_COUNTprivate val STRIDE TOTAL_COMPONENT_COUNT * BYTES_PER_FLOAT目前为止我们只有一些基本定义它们是为分量计数和粒子之间的跨距添加的。让我们继续构建这个类 private var particles:FloatArrayprivate var vertexArray:VertexArrayprivate var maxParticleCount 0private var currentParticleCount 0private var nextParticle 0constructor(maxParticleCount:Int){particles FloatArray(maxParticleCount*TOTAL_COMPONENT_COUNT)vertexArray VertexArray(particles)this.maxParticleCount maxParticleCount}我们现在有了一个存储粒子的浮点数组和一个VertexArrayVertexArra们要发送给OpenGL的数据因为数组的大小是固定的我们还定义了保maxParticleCount。我们将使用currentParticleCount和nextParticle让我们开始构建一个名为addParticle()的新方法 fun addParticle(position:Point,color:Int,direction:Vector,particleStartTime:Float){val particleOffset nextParticle * TOTAL_COMPONENT_COUNTvar currentOffset particleOffsetnextParticleif(currentParticleCount maxParticleCount){currentParticleCount}if(nextParticle maxParticleCount){nextParticle 0} 要创建新的粒子首先要传入位置、颜色、方向和粒子创建时间。颜色作为Android的颜色定义被传递进来我们需要用Android的Color类把这个颜色分解为单独的分量。 在给数组加入新的粒子之前我们需要计算它需要存在哪里。因为所有的粒子都一起存在我们的数组中它类似于一种无定形的blob二进制大对象。为了计算正确的偏移值我们使用nextParticle存储下一个粒子的编号其中第一个粒子从0开始编号。然后我们可以通过把nextParticle与每个粒子的分量计数相乘得到偏移值。我们把这个偏移值存储在 particleOffset和 currentOffset中我们使用 particleOffset记住新粒子从哪里开始而用currentOffset记住新粒子的每个属性的位置。 一个新粒子每次被添加进来时我们就给nextParticle增加1当到了数组的结尾处我们就从0开始以便回收最旧的粒子。我们也需要记录有多少个粒子需要被绘制出来为此一个新粒子每次被加入的时候我们都增加currentParticleCount但要把它限制在最大粒子数内。 我们已经解释了这些操作接下来让我们把这个新的粒子数据写到数组中 particles[currentOffset] position.xparticles[currentOffset] position.yparticles[currentOffset] position.zparticles[currentOffset] Color.red(color)/255fparticles[currentOffset] Color.green(color)/255fparticles[currentOffset] Color.blue(color)/255fparticles[currentOffset] direction.xparticles[currentOffset] direction.yparticles[currentOffset] direction.zparticles[currentOffset] particleStartTime首先存进的是位置然后是颜色使用Android的Color类分解出每个分量紧接着是方向向量最后是粒子创建时间。Android的Color类返回的分量范围是从0到255而OpenGL期望的范围是从0到1因此通过用每个分量都除以255我们把它从Android的范围转换为OpenGL期望的范围。 我们还需要把这个新的粒子复制到本地缓冲区以便OpenGL可以存取这些新的数据因此让我们用下面的方法调用完成addParticle() vertexArray.updateBuffer(particles,particleOffset,TOTAL_COMPONENT_COUNT)我们只想复制这些新数据这样就不会浪费时间去复制那些没有改变的数据因此我们传递进起始偏移值和那个计数。由于updateBuffer()作为VertexArray内部的一个新方法我们还需要加入它的定义。为此我们在类的结尾处加入如下代码 fun updateBuffer(vertexData:FloatArray,start:Int,count:Int){floatBuffer.position(start)floatBuffer.put(vertexData,start,count)floatBuffer.position(0)}现在我们可以返回 ParticleSystem并加入一个绑定函数 fun bindData(particleProgram:ParticleShaderProgram){var dataOffset 0vertexArray.setVertexAttribPointer(dataOffset,particleProgram.aPositionLocation,POSITION_COMPONENT_COUNT,STRIDE)dataOffset POSITION_COMPONENT_COUNTvertexArray.setVertexAttribPointer(dataOffset,particleProgram.aColorLocation,COLOR_COMPONENT_COUNT,STRIDE)dataOffset COLOR_COMPONENT_COUNTvertexArray.setVertexAttribPointer(dataOffset,particleProgram.aDirectionVectorLocation,VECTOR_COMPONENT_COUNT,STRIDE)dataOffset VECTOR_COMPONENT_COUNTvertexArray.setVertexAttribPointer(dataOffset,particleProgram.aParticleStartTimeLocation,PARTICLE_START_TIME_COMPONENT_COUNT,STRIDE)}这又只是一段样板式的代码它遵循与前面几篇一样的模式在着色器程序中把顶点数据与正确的属性绑定并小心遵守我们在addParticle()中所使用的顺序。如果我们把颜色和方向向量的顺序搞混了或者犯了此类错误当我们绘制那些粒子时我们将看到相当抽象的结果。 让我们加入一个draw()函数来结束这个类 fun draw(){GLES20.glDrawArrays(GLES20.GL_POINTS,0,currentParticleCount)}我们现在就实现了一个粒子系统。这个系统可以让我们添加一定量的粒子回收旧的粒子并在内存中有效地定位那些彼此相邻的粒子。 添加一个粒子喷泉 有了这个粒子系统我们现在需要某个程序它可以为我们实际生成一些粒子并把它们添加到粒子系统中。让我们创建一个粒子喷泉继续创建一个名为“ParticleShooter”的新类并加入如下代码 class ParticleShooter(var position:Point,var direction:Vector,var color:Int) {}我们已经给定了这个粒子发射器的位置、方向和颜色当我们创建新的粒子时我们只要把这些直接传递给粒子系统。让我们继续编写这个粒子发射器 fun addParticles(particleSystem: ParticleSystem,currentTime:Float,count:Int){for(i in 0 until count) {particleSystem.addParticle(position, color, direction, currentTime)}}在 addParticles()中我们传进了粒子系统、要添加多少粒子以及粒子系统的当前时间。我们现在已经有了所有的组件只需要在Renderer类中加入一些调用把这一切组合起来。 绘制粒子系统 只需要给ParticlesRenderer加入一些代码就能最终看到这些粒子了。让我们以下面的定义开始 class ParticlesRenderer:Renderer {var context:Contextvar projectionMatrix FloatArray(16)var viewMatrix FloatArray(16)var viewProjectionMatrix FloatArray(16)lateinit var particleProgram:ParticleShaderProgramlateinit var particleSystem: ParticleSystemlateinit var redParticleShooter: ParticleShooterlateinit var greenParticleShooter: ParticleShooterlateinit var blueParticleShooter: ParticleShootervar globalStartTime:Long 0Lconstructor(context: Context){this.context context}这里定义了Android的Context和那些矩阵的标准变量以及粒子着色器、粒子系统和三个粒子发射器的变量。我们还定义了全局启动时间的变量和一个标准构造函数。 接下来让我们定义onSurfaceCreated()的内容 override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {GLES20.glClearColor(0.0f,0.0f,0.0f,0.0f)particleProgram ParticleShaderProgram(context)particleSystem ParticleSystem(10000)globalStartTime System.nanoTime()val particleDirection Vector(0f,0.5f,0f)redParticleShooter ParticleShooter(Point(-1f,0f,0f),particleDirection, Color.rgb(255,50,5))greenParticleShooter ParticleShooter(Point(0f,0f,0f),particleDirection, Color.rgb(25,255,25))blueParticleShooter ParticleShooter(Point(1f,0f,0f),particleDirection, Color.rgb(5,50,255))}我们把清屏的颜色设为黑色初始化粒子着色器程序并用一万个粒子的最大限量初始化一个新的粒子系统然后我们使用System.nanoTime()获得当前系统时间并用它设置全局启动时间。我们想在粒子系统中使用浮点数时间因此当粒子系统被初始化时当前时间将是0.0在此时创建的粒子其创建时间将是0.0。5秒以后新粒子的创建时间是5.0。为此我们可以用当前系统时间与globalStartTime的差值作为创建时间因为System.nanoTime()返回以纳秒为单位的时间我们只要把这个差值除以一万亿就可以转换为秒。 这个方法的下半部分建立了三个粒子喷泉。每个喷泉由一个粒子发射器表示每个发射器都将按照particleDirection定义的方向或者沿y轴垂直向上发射它的粒子。我们把这三个喷泉按照从左到右的顺序排列并且设置了它们的颜色第一个是红色第二个是绿色第三个是蓝色。 让我们加入 onSurfaceChanged()的定义 override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {GLES20.glViewport(0,0,width,height)Matrix.perspectiveM(projectionMatrix,0,45f,width.toFloat()/height.toFloat(),1f,10f)Matrix.setIdentityM(viewMatrix,0)Matrix.translateM(viewMatrix,0,0f,-1.5f,-5f)Matrix.multiplyMM(viewProjectionMatrix,0,projectionMatrix,0,viewMatrix,0)}这是一个标准定义它用一个常规的透视投影和视图矩阵把物体放在正确的空间中。让我们为onDrawFrame()加入如下定义完成这个渲染器 override fun onDrawFrame(p0: GL10?) {GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)var currentTime (System.nanoTime() - globalStartTime) / 1000000000fredParticleShooter.addParticles(particleSystem,currentTime,5)greenParticleShooter.addParticles(particleSystem,currentTime,5)blueParticleShooter.addParticles(particleSystem,currentTime,5)particleProgram.useProgram()particleProgram.setUniforms(viewProjectionMatrix,currentTime)particleSystem.bindData(particleProgram)particleSystem.draw()}每次一个新帧被绘制时我们都计算当前时间并把它传给着色器。它会告诉着色器粒子自从被创建后移动了多远。我们也为每个喷泉生成了5个新的粒子然后用粒子着色程序绘制这些粒子。 运行一下这个程序几秒钟后它应该看上去如下图所示。 我们现在有了一个能工作的系统随着粒子运行时间的变化我们会看到它由明变暗的效果但是它看起来还是很奇怪不是吗当粒子向上移动时它们不应该扩散开么因为重力的作用它们不应该向下回落么接下来我们要解决这些问题及其他更多的问题。 扩散粒子 我们要做的第一件事是扩散粒子我们也将变化每个粒子的速度让每个粒子喷泉有更多的变化。让我们回到ParticleShooter类将其改造为如下代码 class ParticleShooter1(var position:Point, var direction:Vector, var color:Int, var angleVariance:Float, var speedVariance:Float) {var rotationMatrix FloatArray(16)var directionVector FloatArray(4)var resultVector FloatArray(4)init {directionVector[0] direction.xdirectionVector[1] direction.ydirectionVector[2] direction.z}每个发射器都将有一个角度变化量用来控制粒子的扩散以及一个速度变化量用来改变每个粒子的速度。我们也有一个矩阵和两个向量因此我们可以使用Android的Matrix类做些数学运算。 现在我们只需要更新addParticles()应用角度和速度的变化量。按如下代码更新 for循环的内容 Matrix.setRotateEulerM(rotationMatrix,0,(Random.nextFloat() - 0.5f)*angleVariance,(Random.nextFloat() - 0.5f)*angleVariance,(Random.nextFloat() - 0.5f)*angleVariance)Matrix.multiplyMV(resultVector,0,rotationMatrix,0,directionVector,0)var speedAdjustment 1f Random.nextFloat() * speedVariancevar thisDirection Vector(resultVector[0] * speedAdjustment,resultVector[1] * speedAdjustment,resultVector[2] * speedAdjustment)particleSystem.addParticle(position,color,thisDirection,currentTime)要改变发射角度我们使用Android的Matrix.setRotateEulerM()创建一个旋转矩阵它会用angleVariance的一个随机量改变发射角度其单位是度。接下来我们把这个矩阵与方向向量相乘得到一个角度稍小的旋转向量。要调整速度我们把方向向量的每一个分量都与相同的speedVariance的随机调整值相乘。一旦完成这些我们就通过调用particleSystem.addParticle()添加这个新的粒子。 现在需要更新ParticlesRenderer调整新的构造函数参数。修改onSurfaceCreated()以便粒子发射器可以按如下方式创建出来 override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {GLES20.glClearColor(0.0f,0.0f,0.0f,0.0f)val angleVarianceInDegrees 5fval speedVariance 1f;particleProgram ParticleShaderProgram(context)particleSystem ParticleSystem(10000)globalStartTime System.nanoTime()val particleDirection Vector(0f,0.5f,0f)redParticleShooter ParticleShooter(Point(-1f,0f,0f),particleDirection, Color.rgb(255,50,5),angleVarianceInDegrees,speedVariance)greenParticleShooter ParticleShooter(Point(0f,0f,0f),particleDirection, Color.rgb(25,255,25),angleVarianceInDegrees,speedVariance)blueParticleShooter ParticleShooter(Point(1f,0f,0f),particleDirection, Color.rgb(5,50,255),angleVarianceInDegrees,speedVariance)}我们的系统已经准备好了每个粒子喷泉都有一个5度的发射角变化量以及一个1单位的发射速度变化量。继续运行这个应用看看我们这次看到了什么。它看起来应该如图下所示。 看起来效果好多了,现在我们需要添加重力把那些粒子拉回地面。 添加重力 任何上升到空中的东西都会掉下来因为地球有吸引力。牛顿受到苹果从树上落下的启发而发现了重力效应他也因此而出名如果我们也给粒子加入重力效应效果看起来会更好。 在地球上每个人都感受到9.8m/s²的加速度如果我落的时间越长它的速度就越快。通过给顶点着色器加入一个容易地在代码中实现这个效果。打开particle_vertex_shader.glsl在v_ElapsedTime赋值语句之后加入如下代码行 float gravityFactor v_ElapsedTime * v_ElapsedTime / 8.0;它通过应用重力加速度公式和粒子运行时间的平方值计算得到一个加速重力因子我们还把它除以8以弱化这个效果。数值8是被任意使用的可以使用其他任何数值同样也能获得不错的效果。现在需要给当前的位置应用这个重力因子在currentPosition赋值语句之后给顶点着色器加入如下代码 currentPosition.y - gravityFactor;让我们再次运行这个应用看看会发生什么。它看起来应该如图下图所示所示。 现在我们看到每个向上移动的粒子都渐渐慢下来并最终向地面回落。我们还可以让它更好看一些较暗的粒子覆盖了那些较明亮的这看起来有点奇怪。 累加混合技术混合粒子 当我们在OpenGL中实现各种效果时我们不得不经常回想我们要努力仿制的那个效果。如果把这三个粒子流想象成一个喷射的烟花就像我们在烟花表演上看到的一样那我们应该期望这些粒子可以发光粒子越多它们就应该越亮。模仿这个效果的方法之一是使用累加混合技术。 让我们使能混合技术在onSurfaceCreated()方法里为ParticlesRenderer类加入如下代码 GLES20.glEnable(GLES20.GL_BLEND)GLES20.glBlendFunc(GLES20.GL_ONE,GLES20.GL_ONE)就是它!我们首先要使能混合技术然后设置混合模式为累加混合。为了更好地理解这是怎么工作的让我们看一下OpenGL的默认混合公式 输出(源因子源片段)(目标因子目标片段) 在OpenGL里混合技术的工作原理是把片段着色器的结果和已经在帧缓冲区中的颜色进行混合。源片段的值来自于片段着色器目标片段的值就是已经在帧缓冲区中的值源因子和目标因子的值是通过调用glBlendFunc()配置的。在我们刚刚添加的代码中调用glBlendFunc()时我们把每个因子都设为GL_ONE它把混合公式变为如下的公式 输出(GL_ONE源片段)(GL_ONE目标片段) 通过这个混合模式来自片段着色器的片段就被累加到已经存在于屏幕上的片段了这就是为什么它叫累加混合技术。还有其他更多的混合模式可以在Khronos网站上在线查看。 我们的粒子现在看上去被点亮了因为它们混合在一起了。我们还要记住OpenGL限定每一个颜色分量的值因此如果我们给纯绿色加上纯绿色得到的还是纯绿色。然而如果我们只把一小点的红色累加到那个绿色上足够多次实际上也会偏移它的色调最终得到黄色再累加一点蓝色到那个黄色足够多的次数我们就会看到白色。 考虑到OpenGL的限值特性我们可以实现一些优美的效果。比如在下图中我们的红色烟花喷泉在它的最亮处实际上有点发黄这是因为我们给它的基色上加入了一点绿色和稍少一点的蓝色。 自定义点的外形 你可能已经注意到了这些点被渲染为小的四方块其每条边上的像素数量都等于gl_PointSize的值。我们实际上可以使用另一个特殊的 OpenGL变量 gl_PointCoord自定义这些点的外形。对于每个点当调用片段着色器时我们都会得到一个二维的gl_PointCoord坐标空间在每个轴上其分量的范围都是从0到1其取值依赖于点上的哪个片段当前正在被渲染。 要知道这是怎么工作的我们首先要使用gl_PointCoord把片段绘制为圆而不是方形。我们怎么做呢渲染每个点时相对于gl_PointCoord上的每个轴来说其片段的位置范围都是从0到1因此我们把点的圆心放在(0.5,0.5)其每条边都有0.5单位的空间。换句话说点的半径是0.5。要绘制一个圆我们所要做的就是只绘制那些位于半径内的片段。 首先让我们调高点的大小以便使它更容易被看到。将 particle_vertex_shader.glsl中的gl_PointSize更新为如下值 precision mediump float; varying vec3 v_Color; varying float v_ElapsedTime;void main(){float xDistance 0.5 - gl_PointCoord.x;float yDistance 0.5 - gl_PointCoord.y;float distanceFromCenter sqrt(xDistance*xDistance yDistance*yDistance);if(distanceFromCenter 0.5){discard;} else {gl_FragColor vec4(v_Color / v_ElapsedTime,1.0);} }用这种方法把一个点绘制为圆其开销有点大但是它能工作。它的工作原理是对于每个片段我们使用勾股定理计算其与圆心的距离。如果那个距离大于0.5单位的半径那么当前的片段就不是圆的一部分我们还使用了特殊的关键词“discard”告诉OpenGL丢掉这个片段否则我们还像以前一样绘制这个片段。 让我们再次运行这个应用它看上去应该如下图所示(去掉混合可能会更容易观察)。 把每个点绘制为一个精灵 我们刚刚学过的技术是可行的但是有时候纹理更有效。使用相同的gl_PointCoord和纹理实际上可以把每个点绘制为一个点精灵。对于每个粒子我们将改动粒子着色器让它使用下图所示的纹理。 要实现本项目中的纹理首先更新片段着色器加入如下uniform uniform sampler2D u_TextureUnit;去掉我们在前一节加入的画圆的逻辑按如下代码更新 gl_FragColor的赋值语句 gl_FragColor vec4(v_Color / v_ElapsedTime,1.0) * texture2D(u_TextureUnit , gl_PointCoord);它会使用gl_PointCoord作为纹理坐标在每个点上绘制一个纹理。纹理的颜色会与点的颜色相乘这样就可以用与以前一样的方式将这些点染上颜色。 我们现在需要给ParticleShaderProgram加入新的uniform。首先加入如下成员变量 var uTextureUnitLocation 0在构造函数的结尾处加入如下代码 uTextureUnitLocation findUniformLocationByName(U_TEXTURE_UNIT)我们需要把 setUniforms()的签名更新为如下代码 fun setUniforms(matrix:FloatArray,elapsedTime:Float,textureId:Int){我们也需要在 setUniforms()的结尾处加人如下代码 GLES20.glActiveTexture(GLES20.GL_TEXTURE0)GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureId)GLES20.glUniform1i(uTextureUnitLocation,0)我们只需要加载这个新的纹理就准备好运行这个应用程序了。打开ParticlesRenderer 并加人下面的新成员变量 var texture:Int 0在 onSurfaceCreated()的结尾处加入如下代码 texture TextureHelper.loadTexture(context,R.drawable.particle_texture)现在我们可以在onDrawFrame()中更新调用particleProgram.setUniforms()了如下代码所示 particleProgram.setUniforms(viewProjectionMatrix,currentTime,texture)最后运行效果如下图。 小结 我们已经讲述了粒子系统的一些基本内容但事实上我们只触及了一些皮毛而已。粒子可以实现很多效果包括逼真的火焰、雨和雪等。我们学习了如何用OpenGL的GL_POINTS模式绘制粒子,我们还进一步讨论了如何用gl_PointCoord及discard关键词自定义点的形状也可以使用纹理更进一步定制点的外形。有了这些能力我们可以实现一些相当优美的效果。
文章转载自:
http://www.morning.fnzbx.cn.gov.cn.fnzbx.cn
http://www.morning.wnbqy.cn.gov.cn.wnbqy.cn
http://www.morning.plqqn.cn.gov.cn.plqqn.cn
http://www.morning.jcbmm.cn.gov.cn.jcbmm.cn
http://www.morning.rqdx.cn.gov.cn.rqdx.cn
http://www.morning.lqqqh.cn.gov.cn.lqqqh.cn
http://www.morning.kscwt.cn.gov.cn.kscwt.cn
http://www.morning.sryhp.cn.gov.cn.sryhp.cn
http://www.morning.hphqy.cn.gov.cn.hphqy.cn
http://www.morning.ghxzd.cn.gov.cn.ghxzd.cn
http://www.morning.jgmdr.cn.gov.cn.jgmdr.cn
http://www.morning.glrzr.cn.gov.cn.glrzr.cn
http://www.morning.sjgsh.cn.gov.cn.sjgsh.cn
http://www.morning.yjfmj.cn.gov.cn.yjfmj.cn
http://www.morning.qmrsf.cn.gov.cn.qmrsf.cn
http://www.morning.ylqb8.cn.gov.cn.ylqb8.cn
http://www.morning.alwpc.cn.gov.cn.alwpc.cn
http://www.morning.rmfw.cn.gov.cn.rmfw.cn
http://www.morning.ryxdf.cn.gov.cn.ryxdf.cn
http://www.morning.prgnp.cn.gov.cn.prgnp.cn
http://www.morning.jphxt.cn.gov.cn.jphxt.cn
http://www.morning.hrzhg.cn.gov.cn.hrzhg.cn
http://www.morning.qggcc.cn.gov.cn.qggcc.cn
http://www.morning.yqwsd.cn.gov.cn.yqwsd.cn
http://www.morning.ltypx.cn.gov.cn.ltypx.cn
http://www.morning.dgsr.cn.gov.cn.dgsr.cn
http://www.morning.nnhrp.cn.gov.cn.nnhrp.cn
http://www.morning.rglp.cn.gov.cn.rglp.cn
http://www.morning.trhrk.cn.gov.cn.trhrk.cn
http://www.morning.fhbhr.cn.gov.cn.fhbhr.cn
http://www.morning.fthqc.cn.gov.cn.fthqc.cn
http://www.morning.haibuli.com.gov.cn.haibuli.com
http://www.morning.ftrpvh.cn.gov.cn.ftrpvh.cn
http://www.morning.wnzgm.cn.gov.cn.wnzgm.cn
http://www.morning.bpmdq.cn.gov.cn.bpmdq.cn
http://www.morning.lnwdh.cn.gov.cn.lnwdh.cn
http://www.morning.thzgd.cn.gov.cn.thzgd.cn
http://www.morning.qbjrf.cn.gov.cn.qbjrf.cn
http://www.morning.dbsch.cn.gov.cn.dbsch.cn
http://www.morning.zcsyz.cn.gov.cn.zcsyz.cn
http://www.morning.mkccd.cn.gov.cn.mkccd.cn
http://www.morning.whclz.cn.gov.cn.whclz.cn
http://www.morning.pkdng.cn.gov.cn.pkdng.cn
http://www.morning.mfrb.cn.gov.cn.mfrb.cn
http://www.morning.807yy.cn.gov.cn.807yy.cn
http://www.morning.rnpnn.cn.gov.cn.rnpnn.cn
http://www.morning.nkjkh.cn.gov.cn.nkjkh.cn
http://www.morning.zsyrk.cn.gov.cn.zsyrk.cn
http://www.morning.jwfqq.cn.gov.cn.jwfqq.cn
http://www.morning.rpkl.cn.gov.cn.rpkl.cn
http://www.morning.wbqk.cn.gov.cn.wbqk.cn
http://www.morning.yhjlg.cn.gov.cn.yhjlg.cn
http://www.morning.psqs.cn.gov.cn.psqs.cn
http://www.morning.znnsk.cn.gov.cn.znnsk.cn
http://www.morning.zdzgf.cn.gov.cn.zdzgf.cn
http://www.morning.yrccw.cn.gov.cn.yrccw.cn
http://www.morning.rqknq.cn.gov.cn.rqknq.cn
http://www.morning.iknty.cn.gov.cn.iknty.cn
http://www.morning.hnk25076he.cn.gov.cn.hnk25076he.cn
http://www.morning.rqkk.cn.gov.cn.rqkk.cn
http://www.morning.lwmzp.cn.gov.cn.lwmzp.cn
http://www.morning.zwsgl.cn.gov.cn.zwsgl.cn
http://www.morning.jbpdk.cn.gov.cn.jbpdk.cn
http://www.morning.ldcsw.cn.gov.cn.ldcsw.cn
http://www.morning.tslwz.cn.gov.cn.tslwz.cn
http://www.morning.gcqkb.cn.gov.cn.gcqkb.cn
http://www.morning.synlt.cn.gov.cn.synlt.cn
http://www.morning.qdrhf.cn.gov.cn.qdrhf.cn
http://www.morning.mmclj.cn.gov.cn.mmclj.cn
http://www.morning.mlgsc.com.gov.cn.mlgsc.com
http://www.morning.sbncr.cn.gov.cn.sbncr.cn
http://www.morning.trtdg.cn.gov.cn.trtdg.cn
http://www.morning.hwsgk.cn.gov.cn.hwsgk.cn
http://www.morning.rjyd.cn.gov.cn.rjyd.cn
http://www.morning.wrkcw.cn.gov.cn.wrkcw.cn
http://www.morning.hjwzpt.com.gov.cn.hjwzpt.com
http://www.morning.yzxlkj.com.gov.cn.yzxlkj.com
http://www.morning.zlxrg.cn.gov.cn.zlxrg.cn
http://www.morning.wmrgp.cn.gov.cn.wmrgp.cn
http://www.morning.fxzlg.cn.gov.cn.fxzlg.cn
http://www.tj-hxxt.cn/news/273591.html

相关文章:

  • 论论坛坛网网站站建建设设网站建设最好的书籍是
  • 水利网站建设东莞详细页设计
  • 中文网站开发语言网站建设营销型号的区别
  • 制作网站图文教程腾讯云 云服务器
  • 江苏省建设工程注册中心网站谷歌浏览器打开就是2345网址导航
  • 做不锈钢的网站有哪些阿里云建站售前咨询
  • 网站开发有哪些框架免费快速网站
  • 网站开发技术有什么pc门户网站是什么意思
  • 做解析视频网站怎么赚钱给建设单位造成损失的
  • 小浪底水利枢纽建设管理局网站html5国内网站
  • 网站 视觉上shopify seo
  • 做网站有虚拟服务器在线购物网站开发项目
  • wordpress 上传网站网站图片特效代码
  • 美橙西安网站备案拍照浏阳市商务局网站溪江农贸市场建设
  • 珠海网站建设公司电话化妆品网站建设报告
  • 可以做查询功能的网站毕业设计开题报告网站开发
  • 官方网站建立推广赚钱
  • 滨城网站开发贵州做网站
  • 网站百度搜不到了网页设计外文文献
  • 织梦手机网站源码搜索引擎优化的办法有哪些
  • 台州市网站制作营销品牌有哪些
  • 东台网站建设公司什么是竞价推广
  • 品牌营销网站建设流程小程序源码搭建
  • txt怎么做网站郑州建设教育培训中心
  • 广告联盟上怎么做网站app导航网站源码
  • 织梦网站修改教程基因数据库网站建设
  • 有免费可以做的网站吗上海公交建设公司官网
  • 宜昌网站模板科技尽头
  • 梅州建站教程现在做网站还赚钱吗
  • 龙岗坪地网站建设公司做内贸的电子商务网站典型有