请问大佬关于小游戏webgl渲染中uniform3fv参数的问题
发布于 5 年前 作者 fma 14758 次浏览 来自 问答
  • 当前 Bug 的表现(可附上截图)

使用webgl渲染时,调用 gl.uniform3fv, gl.uniform4fv 等接口设置shader参数时发现以下问题:

以 gl.uniform3fv(dest, v) 为例,如果 v = Float32Array([1,2,3]).subarray(1,2) ,即输入的参数是一个byteoffset != 0 的TypeArray,那么实际运行时该参数的设置结果是错误的,导致游戏显示出现各种问题。

  • 预期表现
  • 复现路径

我们还试过华为,三星的多款Android的手机,均有这个问题。

  • 提供一个最简复现 Demo

测试代码:

let ctx   = canvas.getContext(‘webgl’)

let HEAP32 = new Int32Array(1024 * 1024 * 8)

let global_time = 0;

var aspectRatio;

var vertexArray;

var vertexBuffer;

var vertexNumComponents;

var vertexCount;

var uScalingFactor;

var uGlobalColor;

var uRotationVector;

var aVertexPosition;

var previousTime = 0.0;

var degreesPerSecond = 90.0;

var HEAP = new Float32Array(16);

var currentRotation = 8;

var currentScale = 10;

var currentAngle = 0;

var shaderProgram = null;

var rotationRate = 0;

function compileShader(code, type) {

let gl = ctx;

var shader = gl.createShader(type);

gl.shaderSource(shader, code);

gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

console.log(`Error compiling ${type === gl.VERTEX_SHADER ? “vertex” : “fragment”} shader:`);

console.log(gl.getShaderInfoLog(shader));

}

return shader;

}

function animateScene() {

let gl = ctx;

gl.viewport(0, 0, 320, 528);

gl.clearColor(0.8, 0.9, 1.0, 1.0);

gl.clear(gl.COLOR_BUFFER_BIT);

var radians = currentAngle * Math.PI / 180.0;

HEAP[currentRotation] = Math.sin(radians);

HEAP[currentRotation + 1] = Math.cos(radians);

gl.useProgram(shaderProgram);

uScalingFactor = gl.getUniformLocation(shaderProgram, “uScalingFactor”);

uGlobalColor = gl.getUniformLocation(shaderProgram, “uGlobalColor”);

uRotationVector = gl.getUniformLocation(shaderProgram, “uRotationVector”);

gl.uniform2fv(uScalingFactor, HEAP.subarray(currentScale, currentScale + 2));

gl.uniform2fv(uRotationVector, HEAP.subarray(currentRotation, currentRotation + 2));

var rot = gl.getUniform(shaderProgram, uRotationVector);

if (rot[0] != HEAP[currentRotation] || rot[1] != HEAP[currentRotation + 1])

console.log(“buggy”);

else

console.log(“ok”);

gl.uniform4fv(uGlobalColor, [0.1, 0.7, 0.2, 1.0]);

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

aVertexPosition = gl.getAttribLocation(shaderProgram, “aVertexPosition”);

gl.enableVertexAttribArray(aVertexPosition);

gl.vertexAttribPointer(aVertexPosition, vertexNumComponents, gl.FLOAT, false, 0, 0);

gl.drawArrays(gl.TRIANGLES, 0, vertexCount);

window.requestAnimationFrame(function (currentTime) {

var deltaAngle = ((currentTime - previousTime) / 1000.0) * degreesPerSecond;

currentAngle = (currentAngle + deltaAngle) % 360;

previousTime = currentTime;

animateScene();

});

}

/**

* 游戏主函数

*/

export default class Main {

constructor() {

// 维护当前requestAnimationFrame的id

this.aniId    = 0

console.log(“start !!!”)

this.startup();

}

startup() {

let gl = ctx;

var shaderSet = [

{

type: gl.VERTEX_SHADER,

code: “attribute vec2 aVertexPosition;” +

“uniform vec2 uScalingFactor;” +

“uniform vec2 uRotationVector;” +

“void main() {” +

“vec2 rotatedPosition = vec2(aVertexPosition.x * uRotationVector.y + aVertexPosition.y * uRotationVector.x,” +

“aVertexPosition.y * uRotationVector.y - aVertexPosition.x * uRotationVector.x);” +

“gl_Position = vec4(rotatedPosition * uScalingFactor, 0.0, 1.0);” +

“}”

},

{

type: gl.FRAGMENT_SHADER,

code: “precision highp float;” +

“uniform vec4 uGlobalColor;” +

“void main() { gl_FragColor = uGlobalColor; }”

}

];

shaderProgram = this.buildShaderProgram(shaderSet);

aspectRatio = 320 / 528;

HEAP[currentRotation] = 0;

HEAP[currentRotation + 1] = 1;

HEAP[currentScale] = 1;

HEAP[currentScale + 1] = aspectRatio;

vertexArray = new Float32Array([

-0.5, 0.5, 0.5, 0.5, 0.5, -0.5,

-0.5, 0.5, 0.5, -0.5, -0.5, -0.5

]);

vertexBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

gl.bufferData(gl.ARRAY_BUFFER, vertexArray, gl.STATIC_DRAW);

vertexNumComponents = 2;

vertexCount = vertexArray.length / vertexNumComponents;

currentAngle = 0.0;

rotationRate = 6;

animateScene();

}

buildShaderProgram(shaderInfo) {

let gl = ctx;

var program = gl.createProgram();

shaderInfo.forEach(function (desc) {

var shader = compileShader(desc.code, desc.type);

if (shader) gl.attachShader(program, shader);

});

gl.linkProgram(program)

if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {

console.log(“Error linking shader program:”);

console.log(gl.getProgramInfoLog(program));

}

return program;

}

// 实现游戏帧循环

}

2 回复

我遇到一个类似的问题,微信里面没法用x-shader。今天找到一个办法,成功在微信上渲染出来效果。

方法如下:



就这个问题,我们研究过了cocos等引擎的处理,它们的做法都是直接 new 一个新的 TypeArray 来保证实际传入的 TypeArray的byteoffset一定为0。即:

v= new Float32Array( new Float32Array([1,2,3]).subarray(1,2))

但这样以来其实是会产生一定的garbage的,因此希望知道这个问题的实际机制是什么?微信这边是否可以帮忙fix掉?

回到顶部