渲染的流程有以下几步:1)顶点数据的输入:顶点数据用来为后面的顶点着色器等阶段提供处理的数据。2)顶点着色器:顶点着色器主要功能是进行坐标变换。3)几何着色器:与顶点着色器不同,几何着色器的输入是完整的图元(比如,点),输出可以是一个或多个其他的图元(比如,三角面),或者不输出任何的图元,几何着色器是可选的。4)图元组装、光栅化:图元组装将输入的顶点组装成指定的图元,经过图元组装以及屏幕映射阶段后,我们将物体坐标变换到了窗口坐标,光栅化是个离散化的过程,将3D连续的物体转化为离散屏幕像素点的过程。5)片元着色器(片段着色器):片元着色器用来决定屏幕上像素的最终颜色。6)混合测试:渲染的最后一个阶段是测试混合阶段。测试包括裁切测试、Alpha测试、模板测试和深度测试。没有经过测试的片段会被丢弃,不需要进行混合阶段,经过测试的片段会进入混合阶段。经过以上几个步骤,OpenGL就能将最终的图形显示到屏幕上。在OpenGL绘制流程中,我们能够编码的就是Vertex Shader(顶点着色器) 和 Fragment Shader(片元着色器)。这也是渲染过程中必备的2个着色器。Vertex Shader处理从客户端输入的数据、应用变换、进行其他的类型的数学运算来计算光照效果、位移、颜色值等。比如为了渲染共有3个顶点的三角形,Vertex Shader将执行3次,也就是为了每个顶点执行一次。图中的3个顶点已经组合在一起,而三角形也已经逐个片段的进行了光栅化。每个片段通过执行Fragment Shader进行填充。Fragment Shader会输出我们屏幕上看到的最终颜色值。在绘制图形的时候,我们会使用到OpenGL的多种状态变量,例如当前的颜色,控制当前视图和投影变换、直线和多边形点画模式、多边形绘图模式、像素包装约定、光照的位置和特征以及被绘制物体的材料属性等。可以设置它的各种状态(或模式),然后让这些状态一直生效,直到再次修改它们。以把当前颜色设置为白色、红色或其他任何颜色,在此之后绘制的所有物体都将使用这种颜色,直到再次把当前颜色设置为其他颜色。许多表示模式的状态变量可以用glEnable()和glDisable()。所以我们说OpenGL是一个状态机。因为OpenGL在渲染处理过程中会顺序执行一系列操作,就如流水线作业一样,所以我们将OpenGL绘制的流程称为渲染管线,包括固定管线和可编程管线。我们使用的是可编程管线,在可编程管线里,顶点的位置、颜色、贴图座标、贴图传进来之后,如何对数据进行改动,产生的片元如何生成结果,可以很自由地控制。下面就简单介绍一下管线和在可变编程管线中必不可少的GLSL(着色器语言)。管线:渲染管线可以理解为渲染流水线。指的是输入需要渲染的3D物体的相关描述信息数据(例:顶点坐标、顶点颜色、顶点纹理等),经过渲染管线一系列的变化和渲染过程,输出一帧最终的图像。简单理解就是一堆原始图形数据经过一个输送管道,期间经过各种变化处理最终出现展示到屏幕的过程。管线又分为固定管线和可编程管线两种。固定管线:在渲染图像的过程,我们只能通过调用GLShaderManager类的固定管线效果实现一系列的着色器处理。可编程管线:在渲染图像的过程,我们能够使用自定义顶点着色器和片元着色器的去处理数据的过程。由于OpenGL的使用场景非常丰富,固定管线或者存储着色器无法完成的任务,这时我们可以使用可编程管线去处理。OpenGL着色语言(OpenGL Shading Language)是用来在OpenGL中着色编码的语言,也即开发人员写的短小的自定义程序,他们是在GPU(Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程性。它可以得到当前OpenGL 中的状态,GLSL内置变量进行传递。GLSL其使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。GLSL的着色器代码分成2个部分:VertexShader(顶点着色器) 和 Fragment Shader(片元着色器)。着色器(Shader)是用来实现图像渲染的,用来替代固定渲染管线的可编辑程序。其中Vertex Shader(顶点着色器)主要负责顶点的几何关系等的运算,Pixel Shader(像素着色器)主要负责片源颜色等的计算。顶点着色器是一个可编程的处理单元,一般用来处理图形每个顶点变换(旋转/平移/投影等)、光照、材质的应用与计算等顶点的相关操作。顶点着色器是逐顶点运算的程序,每个顶点数据都会执行一次。替代了原有固定管线的顶点变换、光照计算,采用GLSL进行开发 。我们可以根据自己的需求采用着色语言自行开发顶点变换、光照等功能,大大增加了程序的灵活性。顶点着色器工作过程为将原始的顶点几何信息(顶点坐标、颜色、纹理)及其他属性传送到顶点着色器中,经过自定义的顶点着色程序处理产生变化后的顶点位置信息,将变化后的顶点位置信息传递给后续图元装配阶段,对应的顶点纹理、颜色等信息则经光栅化后传递到片元着色器。顶点着色器的输入主要为待处理顶点相应的attribute、uniform、采样器以及临时变量,输出主要为经过顶点着色器后生成的varying及一些内建输出变量。顶点着色器示例代码://顶点位置
attribute vec4 Position;
//纹理坐标
attribute vec2 TextureCoord;
//纹理坐标 用于接收和传递给片元着色器的纹理坐标
varying vec2 varyTextureCoord;
void main() {
gl_Position = Position;
varyTextureCoord = TextureCoord;
}//高精度
precision highp float;
//用于接收顶点着色器的纹理坐标
varying vec2 varyTextureCoord;
//图片纹理
uniform sampler2D Texture;
//图片纹理
uniform sampler2D Texture2;
const vec2 direction = vec2(0.0, 1.0);
void main(){
vec2 p = varyTextureCoord.xy/vec2(1.0).xy;
vec4 color = mix(texture2D(Texture, varyTextureCoord), texture2D(Texture2, varyTextureCoord), step(1.0-p.y,progress));
gl_FragColor = vec4(color);
}attribute vec4 a_position;//传入的顶点坐标
attribute vec2 a_texCoord;//传入的纹理坐标
varying vec2 v_texCoord;//传递给片元着色器的纹理坐标
void main()
{
gl_Position = a_position;//将顶点坐标赋值给OpenGL的内置变量
v_texCoord = a_texCoord;//将传入的纹理坐标传递给片元着色器
}再定义一个片元着色器:precision mediump float;//定义float精度,纹理坐标使用的是一个float类型的二维向量vec2
uniform sampler2D u_texture;//纹理
varying vec2 v_texCoord;//纹理坐标
void main(){
gl_FragColor = texture2D(u_texture, v_texCoord);//2D纹理采样,将颜色赋值给OpenGL的内置变量gl_FragColor
}class SimpleImageRender(private val context: Context) : GLSurfaceView.Renderer {
//顶点坐标
private val vCoordinates = floatArrayOf(
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
)
//纹理坐标
private val textureCoordinates = floatArrayOf(
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
)
//OpenGL程序id
var programId = 0
//顶点坐标句柄
var vCoordinateHandle = 0
//纹理坐标句柄
var textureCoordinateHandle = 0
//纹理id
var textureId = 0
private val vertexBuffer =
ByteBuffer.allocateDirect(vCoordinates.size * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vCoordinates)
private val textureBuffer =
ByteBuffer.allocateDirect(textureCoordinates.size * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(textureCoordinates)
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
vertexBuffer.position(0)
textureBuffer.position(0)
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
//根据顶点着色器和片元着色器编辑链接OpenGL程序
programId =
loadShaderWithResource(context, R.raw.simple_image_vs, R.raw.simple_image_fs)
//获取顶点坐标的句柄
vCoordinateHandle = GLES20.glGetAttribLocation(programId, "a_position")
//获取纹理坐标的句柄
textureCoordinateHandle = GLES20.glGetAttribLocation(programId, "a_texCoord")
//生成纹理
val textureIds = IntArray(1)
GLES20.glGenTextures(1, textureIds, 0)
if (textureIds[0] == 0) {
return
}
textureId = textureIds[0]
//绑定纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
//环绕方式
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT)
//过滤方式
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR)
val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.scene1)
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0)
bitmap.recycle()
}
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
}
override fun onDrawFrame(gl: GL10?) {
//清屏,清理掉颜色的缓冲区
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
//设置清屏的颜色,这里是float颜色的取值范围的[0,1]
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
//使用program
GLES20.glUseProgram(programId)
//设置为可用的状态
GLES20.glEnableVertexAttribArray(vCoordinateHandle)
//size 指定每个顶点属性的组件数量。必须为1、2、3或者4。初始值为4。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))
//stride 指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。
//size 2 代表(x,y),stride 8 代表跨度 (2个点为一组,2个float有8个字节)
GLES20.glVertexAttribPointer(vCoordinateHandle, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer)
GLES20.glEnableVertexAttribArray(textureCoordinateHandle)
GLES20.glVertexAttribPointer(
textureCoordinateHandle,
2,
GLES20.GL_FLOAT,
false,
8,
textureBuffer
)
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
}
}uniform vec2 direction; // = vec2(0.0, 1.0)
vec4 transition (vec2 uv) {
vec2 p = uv + progress * sign(direction);
vec2 f = fract(p);
return mix(
getToColor(f),
getFromColor(f),
step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0)
);
}precision mediump float;
uniform vec2 direction;// = vec2(0.0, 1.0)
uniform float progress;//转场的进度
uniform sampler2D u_texture0;//纹理1
uniform sampler2D u_texture1;//纹理2
varying vec2 v_texCoord;//纹理坐标
vec4 transition (vec2 uv) {
vec2 p = uv + progress * sign(direction);
vec2 f = fract(p);
return mix(
texture2D(u_texture1, f),
texture2D(u_texture0, f),
step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0)
);
}
void main(){
gl_FragColor = transition(v_texCoord);
}attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main()
{
gl_Position = a_position;
v_texCoord = a_texCoord;
}frameIndex++
GLES20.glUseProgram(programId)
GLES20.glEnableVertexAttribArray(vCoordinateHandle)
GLES20.glVertexAttribPointer(vCoordinateHandle, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer)
GLES20.glEnableVertexAttribArray(textureCoordinateHandle)
GLES20.glVertexAttribPointer(
textureCoordinateHandle,
2,
GLES20.GL_FLOAT,
false,
8,
textureBuffer
)
val uTexture0Handle = GLES20.glGetUniformLocation(programId, "u_texture0")
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(
GLES20.GL_TEXTURE_2D,
imageTextureIds[(frameIndex / transitionFrameCount) % imageNum]
)
GLES20.glUniform1i(uTexture0Handle, 0)
val uTexture1Handle = GLES20.glGetUniformLocation(programId, "u_texture1")
GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
GLES20.glBindTexture(
GLES20.GL_TEXTURE_2D,
imageTextureIds[(frameIndex / transitionFrameCount + 1) % imageNum]
)
GLES20.glUniform1i(uTexture1Handle, 1)
val directionHandle = GLES20.glGetUniformLocation(programId, "direction")
GLES20.glUniform2f(directionHandle, 0f, 1f)
val uOffsetHandle = GLES20.glGetUniformLocation(programId, "u_offset")
val offset = (frameIndex % transitionFrameCount) * 1f / transitionFrameCount
GLES20.glUniform1f(uOffsetHandle, offset)
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)interface IDrawer {
//准备阶段,准备程序,资源
fun onPrepare()
//绘制
fun onDraw(frameIndex:Int){}
fun onSurfaceChanged(p0: GL10?, width: Int, height: Int){
}
}class ComposeRender : GLSurfaceView.Renderer {
private var frameIndex = 0//当前绘制了多少帧
private var drawersFrames = 0 //所有的drawer绘制一遍需要的帧数,目前每一个drawer占用200帧
private val framesPerDrawer = 200//每一个IDrawer绘制所需要的帧数,这里暂时固定为200
//使用的IDrawer集合
private val drawers = mutableListOf(
HelloWorldTransitionDrawer(),
SimpleTransitionDrawer(),
PerlinTransitionDrawer(),
)
init {
drawersFrames = drawers.size.times(framesPerDrawer)
}
override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
//设置清屏的颜色,这里是float颜色的取值范围的[0,1]
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
//清屏,清理掉颜色的缓冲区
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
drawers.forEach {
it.onPrepare()
}
}
override fun onSurfaceChanged(p0: GL10?, p1: Int, p2: Int) {
GLES20.glViewport(0, 0, p1, p2)
drawers.forEach {
it.onSurfaceChanged(p0, p1, p2)
}
}
override fun onDrawFrame(p0: GL10?) {
frameIndex++
//清屏,清理掉颜色的缓冲区
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
val offset = frameIndex % drawersFrames
val logicFrame = if (offset == 0) 1 else offset
//计算当前的帧数轮到哪个IDrawer的绘制,让对应的IDrawer进行绘制
drawers.forEachIndexed { index, iDrawer ->
if (logicFrame <= (index + 1).times(framesPerDrawer) && logicFrame >= index.times(
framesPerDrawer
)
) {
iDrawer.onDraw(logicFrame - index.times(framesPerDrawer))
}
}
}
}class HelloWorldTransitionDrawer() : IDrawer {
private val imageNum = 2//需要使用两个图片纹理
//转场需要耗费的帧数,这里固定写200帧
private val transitionFrameCount = 200
private val vCoordinates = floatArrayOf(
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
)
private val textureCoordinates = floatArrayOf(
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
)
var programId = 0
var vCoordinateHandle = 0
var textureCoordinateHandle = 0
var imageTextureIds = IntArray(imageNum)
private val vertexBuffer =
ByteBuffer.allocateDirect(vCoordinates.size * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vCoordinates).position(0)
private val textureBuffer =
ByteBuffer.allocateDirect(textureCoordinates.size * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(textureCoordinates).position(0)
override fun onPrepare() {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
programId =
loadShaderWithResource(
MyApplication.getApp(),
R.raw.helloworld_transition_vs,
R.raw.helloworld_transition_fs
)
vCoordinateHandle = GLES20.glGetAttribLocation(programId, "a_position")
textureCoordinateHandle = GLES20.glGetAttribLocation(programId, "a_texCoord")
//生成纹理
val textureIds = IntArray(1)
GLES20.glGenTextures(1, textureIds, 0)
if (textureIds[0] == 0) {
return
}
loadTextures(intArrayOf(R.drawable.scene1, R.drawable.scene2))
}
override fun onDraw(frameIndex:Int) {
//使用program
GLES20.glUseProgram(programId)
//设置为可用的状态
GLES20.glEnableVertexAttribArray(vCoordinateHandle)
//size 指定每个顶点属性的组件数量。必须为1、2、3或者4。初始值为4。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))
//stride 指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。
//size 2 代表(x,y),stride 8 代表跨度 (2个点为一组,2个float有8个字节)
GLES20.glVertexAttribPointer(vCoordinateHandle, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer)
GLES20.glEnableVertexAttribArray(textureCoordinateHandle)
GLES20.glVertexAttribPointer(
textureCoordinateHandle,
2,
GLES20.GL_FLOAT,
false,
8,
textureBuffer
)
val uTexture0Handle = GLES20.glGetUniformLocation(programId, "u_texture0")
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(
GLES20.GL_TEXTURE_2D,
imageTextureIds[0]
)
GLES20.glUniform1i(uTexture0Handle, 0)
val uTexture1Handle = GLES20.glGetUniformLocation(programId, "u_texture1")
GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
GLES20.glBindTexture(
GLES20.GL_TEXTURE_2D,
imageTextureIds[1]
)
GLES20.glUniform1i(uTexture1Handle, 1)
val directionHandle = GLES20.glGetUniformLocation(programId, "direction")
GLES20.glUniform2f(directionHandle, 0f, 1f)
val uOffsetHandle = GLES20.glGetUniformLocation(programId, "u_offset")
val offset = (frameIndex % transitionFrameCount) * 1f / transitionFrameCount
GLES20.glUniform1f(uOffsetHandle, offset)
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
}
private fun loadTextures(resIds: IntArray) {
if (resIds.isEmpty()) return
//直接生成两个纹理
GLES20.glGenTextures(2, imageTextureIds, 0)
resIds.forEachIndexed { index, resId ->
if (imageTextureIds.indexOfFirst {
it == 0
} == 0) return
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index)
//绑定纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imageTextureIds[index])
//环绕方式
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT)
//过滤方式
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR
)
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR
)
val bitmap = BitmapFactory.decodeResource(MyApplication.getApp().resources, resId)
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0)
bitmap.recycle()
}
}
}我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h