- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当我读到 OpenGL/WebGL 的性能时,我几乎听说要减少绘制调用。所以我的问题是我只使用 4 个顶点来绘制纹理四边形。这意味着通常我的 vbo 只包含 4 个顶点。
基本上
gl.bindBuffer(gl.ARRAY_BUFFER,vbo);
gl.uniformMatrix4fv(matrixLocation, false, modelMatrix);
gl.drawArrays(gl.TRIANGLE_FAN,0, vertices.length/3);
gl.bindBuffer(gl.ARRAY_BUFFER,vbo);
gl.uniformMatrix4fv(matrixLocation, false, modelMatrix);
gl.drawArrays(gl.TRIANGLE_FAN, 0, vertices.length/3);
gl.uniformMatrix4fv(matrixLocation, false, anotherModelMatrix);
gl.drawArrays(gl.TRIANGLE_FAN,0, vertices.length/3);
....// repeat until all textures are rendered
最佳答案
第一个问题是,重要吗?
如果您的收入少于 1000,甚至可能是 2000,则绘制调用可能无关紧要。易于使用比大多数其他解决方案更重要。
如果你真的需要很多四边形,那么有很多解决方案。一种是将 N 个四边形放入单个缓冲区中。 See this presentation .然后将位置、旋转和缩放放入其他缓冲区或纹理中,并计算着色器内的矩阵。
换句话说,对于带纹理的四边形,人们通常将顶点位置和 texcoords 放在像这样排序的缓冲区中
p0, p1, p2, p3, p4, p5, // buffer for positions for 1 quad
t0, t1, t2, t3, t4, t5, // buffer for texcoord for 1 quad
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, ... // positions for N quads
t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, ... // texcoords for N quads
s0, s0, s0, s0, s0, s0, s1, s1, s1, s1, s1, s1, s2, ... // scales for N quads
w0, w0, w0, w0, w0, w0, w1, w1, w1, w1, w1, w1, w2, ... // world positions for N quads
attribute vec3 position;
attribute vec2 texcoord;
attribute vec3 worldPosition;
attribute vec3 scale;
uniform mat4 view; // inverse of camera
uniform mat4 camera; // inverse of view
uniform mat4 projection;
varying vec2 v_texcoord;
void main() {
// Assuming we want billboards (quads that always face the camera)
vec3 localPosition = (camera * vec4(position * scale, 0)).xyz;
// make quad points at the worldPosition
vec3 worldPos = worldPosition + localPosition;
gl_Position = projection * view * vec4(worldPos, 1);
v_texcoord = texcoord; // pass on texcoord to fragment shader
}
gl.bufferData
上传所有这些。
const vs = `
attribute vec3 position;
attribute vec2 texcoord;
attribute vec3 worldPosition;
attribute vec2 scale;
uniform mat4 view; // inverse of camera
uniform mat4 camera; // inverse of view
uniform mat4 projection;
varying vec2 v_texcoord;
void main() {
// Assuming we want billboards (quads that always face the camera)
vec3 localPosition = (camera * vec4(position * vec3(scale, 1), 0)).xyz;
// make quad points at the worldPosition
vec3 worldPos = worldPosition + localPosition;
gl_Position = projection * view * vec4(worldPos, 1);
v_texcoord = texcoord; // pass on texcoord to fragment shader
}
`;
const fs = `
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D texture;
void main() {
gl_FragColor = texture2D(texture, v_texcoord);
}
`;
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
// compiles and links shaders and looks up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const numQuads = 100000;
const positions = new Float32Array(numQuads * 6 * 2);
const texcoords = new Float32Array(numQuads * 6 * 2);
const worldPositions = new Float32Array(numQuads * 6 * 3);
const basePositions = new Float32Array(numQuads * 3); // for JS
const scales = new Float32Array(numQuads * 6 * 2);
const unitQuadPositions = [
-.5, -.5,
.5, -.5,
-.5, .5,
-.5, .5,
.5, -.5,
.5, .5,
];
const unitQuadTexcoords = [
0, 0,
1, 0,
0, 1,
0, 1,
1, 0,
1, 1,
];
for (var i = 0; i < numQuads; ++i) {
const off3 = i * 6 * 3;
const off2 = i * 6 * 2;
positions.set(unitQuadPositions, off2);
texcoords.set(unitQuadTexcoords, off2);
const worldPos = [rand(-100, 100), rand(-100, 100), rand(-100, 100)];
const scale = [rand(1, 2), rand(1, 2)];
basePositions.set(worldPos, i * 3);
for (var j = 0; j < 6; ++j) {
worldPositions.set(worldPos, off3 + j * 3);
scales.set(scale, off2 + j * 2);
}
}
const tex = twgl.createTexture(gl, {
src: "http://i.imgur.com/weklTat.gif",
crossOrigin: "",
flipY: true,
});
// calls gl.createBuffer, gl.bufferData
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: { numComponents: 2, data: positions, },
texcoord: { numComponents: 2, data: texcoords, },
worldPosition: { numComponents: 3, data: worldPositions, },
scale: { numComponents: 2, data: scales, },
});
function render(time) {
time *= 0.001; // seconds
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const fov = Math.PI * .25;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = .1;
const zFar = 200;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const radius = 100;
const tm = time * .1
const eye = [Math.sin(tm) * radius, Math.sin(tm * .9) * radius, Math.cos(tm) * radius];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
// calls gl.uniformXXX
twgl.setUniforms(programInfo, {
texture: tex,
view: view,
camera: camera,
projection: projection,
});
// update all the worldPositions
for (var i = 0; i < numQuads; ++i) {
const src = i * 3;
const dst = i * 6 * 3;
for (var j = 0; j < 6; ++j) {
const off = dst + j * 3;
worldPositions[off + 0] = basePositions[src + 0] + Math.sin(time + i) * 10;
worldPositions[off + 1] = basePositions[src + 1] + Math.cos(time + i) * 10;
worldPositions[off + 2] = basePositions[src + 2];
}
}
// upload them to the GPU
gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.worldPosition.buffer);
gl.bufferData(gl.ARRAY_BUFFER, worldPositions, gl.DYNAMIC_DRAW);
// calls gl.drawXXX
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function rand(min, max) {
if (max === undefined) {
max = min;
min = 0;
}
return Math.random() * (max - min) + min;
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas />
// id buffer
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3 ....
attribute float id;
...
uniform sampler2D worldPositionTexture; // texture with world positions
uniform vec2 textureSize; // pass in the texture size
...
// compute the texel that contains our world position
vec2 texel = vec2(
mod(id, textureSize.x),
floor(id / textureSize.x));
// compute the UV coordinate to access that texel
vec2 uv = (texel + .5) / textureSize;
vec3 worldPosition = texture2D(worldPositionTexture, uv).xyz;
const vs = `
attribute vec3 position;
attribute vec2 texcoord;
attribute float id;
uniform sampler2D worldPositionTexture;
uniform sampler2D scaleTexture;
uniform vec2 textureSize; // texture are same size so only one size needed
uniform mat4 view; // inverse of camera
uniform mat4 camera; // inverse of view
uniform mat4 projection;
varying vec2 v_texcoord;
void main() {
// compute the texel that contains our world position
vec2 texel = vec2(
mod(id, textureSize.x),
floor(id / textureSize.x));
// compute the UV coordinate to access that texel
vec2 uv = (texel + .5) / textureSize;
vec3 worldPosition = texture2D(worldPositionTexture, uv).xyz;
vec2 scale = texture2D(scaleTexture, uv).xy;
// Assuming we want billboards (quads that always face the camera)
vec3 localPosition = (camera * vec4(position * vec3(scale, 1), 0)).xyz;
// make quad points at the worldPosition
vec3 worldPos = worldPosition + localPosition;
gl_Position = projection * view * vec4(worldPos, 1);
v_texcoord = texcoord; // pass on texcoord to fragment shader
}
`;
const fs = `
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D texture;
void main() {
gl_FragColor = texture2D(texture, v_texcoord);
}
`;
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const ext = gl.getExtension("OES_texture_float");
if (!ext) {
alert("Doh! requires OES_texture_float extension");
}
if (gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) < 2) {
alert("Doh! need at least 2 vertex texture image units");
}
// compiles and links shaders and looks up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const numQuads = 50000;
const positions = new Float32Array(numQuads * 6 * 2);
const texcoords = new Float32Array(numQuads * 6 * 2);
const ids = new Float32Array(numQuads * 6);
const basePositions = new Float32Array(numQuads * 3); // for JS
// we need to pad these because textures have to rectangles
const size = roundUpToNearest(numQuads * 4, 1024 * 4)
const worldPositions = new Float32Array(size);
const scales = new Float32Array(size);
const unitQuadPositions = [
-.5, -.5,
.5, -.5,
-.5, .5,
-.5, .5,
.5, -.5,
.5, .5,
];
const unitQuadTexcoords = [
0, 0,
1, 0,
0, 1,
0, 1,
1, 0,
1, 1,
];
for (var i = 0; i < numQuads; ++i) {
const off2 = i * 6 * 2;
const off4 = i * 4;
// you could even put these in a texture OR you can even generate
// them inside the shader based on the id. See vertexshaderart.com for
// examples of generating positions in the shader based on id
positions.set(unitQuadPositions, off2);
texcoords.set(unitQuadTexcoords, off2);
ids.set([i, i, i, i, i, i], i * 6);
const worldPos = [rand(-100, 100), rand(-100, 100), rand(-100, 100)];
const scale = [rand(1, 2), rand(1, 2)];
basePositions.set(worldPos, i * 3);
for (var j = 0; j < 6; ++j) {
worldPositions.set(worldPos, off4 + j * 4);
scales.set(scale, off4 + j * 4);
}
}
const tex = twgl.createTexture(gl, {
src: "http://i.imgur.com/weklTat.gif",
crossOrigin: "",
flipY: true,
});
const worldPositionTex = twgl.createTexture(gl, {
type: gl.FLOAT,
src: worldPositions,
width: 1024,
minMag: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE,
});
const scaleTex = twgl.createTexture(gl, {
type: gl.FLOAT,
src: scales,
width: 1024,
minMag: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE,
});
// calls gl.createBuffer, gl.bufferData
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: { numComponents: 2, data: positions, },
texcoord: { numComponents: 2, data: texcoords, },
id: { numComponents: 1, data: ids, },
});
function render(time) {
time *= 0.001; // seconds
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const fov = Math.PI * .25;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = .1;
const zFar = 200;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const radius = 100;
const tm = time * .1
const eye = [Math.sin(tm) * radius, Math.sin(tm * .9) * radius, Math.cos(tm) * radius];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
// update all the worldPositions
for (var i = 0; i < numQuads; ++i) {
const src = i * 3;
const dst = i * 3;
worldPositions[dst + 0] = basePositions[src + 0] + Math.sin(time + i) * 10;
worldPositions[dst + 1] = basePositions[src + 1] + Math.cos(time + i) * 10;
worldPositions[dst + 2] = basePositions[src + 2];
}
// upload them to the GPU
const width = 1024;
const height = worldPositions.length / width / 4;
gl.bindTexture(gl.TEXTURE_2D, worldPositionTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, worldPositions);
// calls gl.uniformXXX, gl.activeTeture, gl.bindTexture
twgl.setUniforms(programInfo, {
texture: tex,
scaleTexture: scaleTex,
worldPositionTexture: worldPositionTex,
textureSize: [width, height],
view: view,
camera: camera,
projection: projection,
});
// calls gl.drawXXX
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function rand(min, max) {
if (max === undefined) {
max = min;
min = 0;
}
return Math.random() * (max - min) + min;
}
function roundUpToNearest(v, round) {
return ((v + round - 1) / round | 0) * round;
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas />
gl.uniformMatrix4fv
时已经这样做了但你只会打两个电话,
gl.bufferData
或
gl.texImage2D
上传新矩阵,然后
gl.drawXXX
画。
关于opengl-es - 如何减少 OpenGL/WebGL 中的绘图调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42473044/
在 settings.py LANGUAGE_CODE = 'es-mx'或 LANGUAGE_CODE = 'es-ar'不起作用,但是 LANGUAGE_CODE = 'es'或 LANGUAGE
我想知道OpenGL ES 2.0和OpenGL ES 3.0之间有什么区别。 OpenGL ES 3.0的主要优点是什么? 最佳答案 总体而言,这些变化通过更大的缓冲区、更多的格式、更多的统一等提高
这是我为此端点使用 Postman localhost:9201/response_v2_862875ee3a88a6d09c95bdbda029ce2b/_search 的请求正文 { "_sour
OpenGL ES 2.0 没有 ES 1.0 那样的 GL_POINT_SMOOTH 定义。这意味着我用来绘制圆圈的代码不再有效: glEnable(GL_POINT_SMOOTH); glPoin
我尝试编译这个着色器: varying vec2 TexCoords; varying vec4 color; uniform sampler2D text; uniform vec3 textCol
我是 OpenGL ES 的新手,我使用的是 OpenGL ES 2.0 版本。我可以在片段着色器中使用按位操作(右移、左移)吗? 最佳答案 OpenGL ES 2.0 没有按位运算符。 ES 3.0
有没有办法只用线画一个三角形? 我认为GL_TRIANGLES选项可使三角形充满颜色。 最佳答案 使用glPolygonMode(face, model)设置填充模式: glPolygonMode(G
我想用一个包含 yuv 数据的采样器在 opengl es 着色器中将 yuv 转换为 rgb。我的代码如下: 1)我将 yuv 数据发送到纹理: GLES20.glTexImage2D(GLES20
我正在使用这样的域: http://www.domain.com/es/blabla.html 我想更改 .es 的/es 部分并将 URLS 转换为类似以下内容: http://www.domain
有谁知道OpenGL ES是否支持GL_TEXTURE_RECTANGLE?我计划将它用于 2D 图形以支持非二次幂图像。我当前的实现使用 alpha=0 填充的 POT 纹理,对于拉伸(stretc
我需要在具有 PowerVR SGX 硬件的 ARM 设备上实现离屏纹理渲染。 一切都完成了(使用了像素缓冲区和 OpenGL ES 2.0 API)。唯一 Unresolved 问题是速度很慢glR
这是一个奇怪的事情。我有一个片段着色器,据我所知只能返回黑色或红色,但它将像素渲染为白色。如果我删除一根特定的线,它会返回我期望的颜色。它适用于 WebGL,但不适用于 Raspberry Pi 上的
我正在考虑将一些 OpenGL 代码移植到 OpenGL ES 并且想知道这段代码到底做了什么: glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT) 因为 g
我正在考虑将一些 OpenGL 代码移植到 OpenGL ES 并且想知道这段代码到底做了什么: glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT) 因为 g
GLSL ES最多可以编译多少个程序?所以假设我创建了 100 个片段着色器,每个都有不同的效果。所以在运行时我编译所有这些并动态地我用 glUseProgram 交换它们。我假设每次我编译一个新的
我正在尝试使用顶点缓冲区对象来绘制圆,并在 iPhone 上的 OpenGL ES 2.0 中启用 GL_POINT_SMOOTH 来绘制点。 我使用以下 ES 1.0 渲染代码在 iPhone 4
为什么在 OpenGL ES 1.x 中缩放(均匀)对象会导致对象变轻? 更有意义的是它会更暗,因为法线被缩小是否也会使对象更暗?但由于某种原因,物体变轻了。当我放大时,对象变得更暗。在我看来,这应该
我正在尝试通过移植 some code 在 iOS 上的 OpenGL ES 2.0 中获得一些阴影效果。来自标准 GL。部分示例涉及将深度缓冲区复制到纹理: glBindTexture(GL_TEX
所以我正在使用 2D 骨骼动画系统。 有 X 个骨骼,每个骨骼至少有 1 个部分(一个四边形,两个三角形)。平均而言,我可能有 20 块骨头和 30 个部分。大多数骨骼都依赖于父骨骼,骨骼会每帧移动。
我在使用 ES 着色器时遇到了一些晦涩难懂的问题,而且我现在几乎没有想法了。 这是一些代码: .. precision mediump float; .. #define STEP (1f/6f) 5
我是一名优秀的程序员,十分优秀!