/**
* @author mrdoob / http://mrdoob.com/
*/
function WebGLAttributes( gl ) { //传入WebGL上下文
var buffers = {}; //用来存储传入渲染管线的数据
function createBuffer( attribute, bufferType ) {
/*bufferType表示数据的类型,可以选择的值有GL_ARRAY_BUFFER和GL_ELEMENT_ARRAY_BUFFER。
1.GL_ARRAY_BUFFER代表存储数据的数组中存储的是顶点数据,
2.GL_ELEMENT_ARRAY_BUFFER代表数组中存储的各个定点的索引
*/
var array = attribute.array; //attribute.array中存储的是几何对象中已经排列好的顶点坐标位置
var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;/*vbo(顶点缓存技术)的相关设置, gl.STATIC_DRAW是将数据存储放置在显存中
当值为gl.DYNAMIC_DRAW时,数据被存储在系统或AGP(加速图形接口)中,方便对其进行修改和读取,可能这里读者会觉得比较复杂,但是毕竟它很大程度上较少了GPU和存储之间的数据交互次数*/
var buffer = gl.createBuffer(); //创建一个缓存对象
gl.bindBuffer( bufferType, buffer ); //激活缓冲区对象
gl.bufferData( bufferType, array, usage ); //用数据分配和初始化缓冲区对象 array:用于初始化缓冲区的对象
attribute.onUploadCallback(); //??????
var type = gl.FLOAT; //type表示当前数据中每个元素的类型,将其默认为gl.FLOAT
/*根据数据存储的数组类型,设置type值。
我们平时使用的Array对象说它是数组,其实是一个从哈希表扩展的结构体。因此它可以提供push、splice等一些列操作。
这就意味着他们的效率是很低的。在JavaScript中也可以创建真正的数组,那就是强类型数组。
这个概念在以前的JavaScript中是没有的,由于现在JavaScript的发展,它变得可以调用一些系统底层的东西比如WebGL。
这些底层的操作需要直接访问内存,而JavaScript本身的Array在内存中是分散无法与底层操作对接,因此引入了这些强类型的数组。
原文链接:https://www.web-tinker.com/article/20101.html
* */
if ( array instanceof Float32Array ) {
type = gl.FLOAT;
} else if ( array instanceof Float64Array ) {
console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
} else if ( array instanceof Uint16Array ) {
type = gl.UNSIGNED_SHORT;
} else if ( array instanceof Int16Array ) {
type = gl.SHORT;
} else if ( array instanceof Uint32Array ) {
type = gl.UNSIGNED_INT;
} else if ( array instanceof Int32Array ) {
type = gl.INT;
} else if ( array instanceof Int8Array ) {
type = gl.BYTE;
} else if ( array instanceof Uint8Array ) {
type = gl.UNSIGNED_BYTE;
}
return {
buffer: buffer,
type: type,
bytesPerElement: array.BYTES_PER_ELEMENT,
version: attribute.version//这里是为了标记此属性的缓存是否需要进行更新,如果attribute的version值大于buffer的version值,则说明需要缓存数据需要更新
};
/*TypedArray.BYTES_PER_ELEMENT 属性代表了强类型数组中每个元素所占用的字节数。
强类型数组对象用来解释为单个元素的字节数是不一样的。常量 BYTES_PER_ELEMENT 表示了特定强类型数组中每个元素所占用的字节数。
各类型其BYTES_PER_ELEMENT值如下所示。
Int8Array.BYTES_PER_ELEMENT; // 1
Uint8Array.BYTES_PER_ELEMENT; // 1
Uint8ClampedArray.BYTES_PER_ELEMENT; // 1
Int16Array.BYTES_PER_ELEMENT; // 2
Uint16Array.BYTES_PER_ELEMENT; // 2
Int32Array.BYTES_PER_ELEMENT; // 4
Uint32Array.BYTES_PER_ELEMENT; // 4
Float32Array.BYTES_PER_ELEMENT; // 4
Float64Array.BYTES_PER_ELEMENT; // 8
出自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT
* */
}
function updateBuffer( buffer, attribute, bufferType ) {
var array = attribute.array;//拿到存储数据的数组
var updateRange = attribute.updateRange;//数组中需要更新的范围(updateRange.offset代表需要更新数据的偏移量和总个数)
gl.bindBuffer( bufferType, buffer ); //确定当前操作的缓冲区
if ( attribute.dynamic === false ) {//如果此项属性不是动态的,则直接将数据进行上传
gl.bufferData( bufferType, array, gl.STATIC_DRAW );
} else if ( updateRange.count === - 1 ) {//如果没有规定需要更新的范围,则将整个数组进行更新
// Not using update ranges
gl.bufferSubData( bufferType, 0, array );
} else if ( updateRange.count === 0 ) {
console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );
} else {
gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );//假设已经在用用程序的一个缓冲区中准备了相同类型的数据,glBufferSubData()将用我们提供的数据替换被绑定的缓冲区对象的一些数据子集。
updateRange.count = -1; // reset range
}
}
//
function get( attribute ) {
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
return buffers[ attribute.uuid ];
}
function remove( attribute ) {
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
var data = buffers[ attribute.uuid ];
if ( data ) {
gl.deleteBuffer( data.buffer ); //在渲染管线中删除相关数据
delete buffers[ attribute.uuid ]; //清除javascript程序中用来存储数据的数组对象
}
}
function update( attribute, bufferType ) {//更新数据缓存的方法
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;//??????这句不太明白什么意思,以后研究清楚了再编辑。。。。。。。。。。
var data = buffers[ attribute.uuid ];//获取当前的数据数组 uuid是唯一标识对象的一种形式,通过uuid可以快速对数据缓存对象进行操作
if ( data === undefined ) {//如果数据数组不存在,则直接进行创建
buffers[ attribute.uuid ] = createBuffer( attribute, bufferType );
} else if ( data.version < attribute.version ) {//如果数据数组存在,并且attribute.version的值高于了data.version,说明attribute中的相关数据需要进行更新
updateBuffer( data.buffer, attribute, bufferType );
data.version = attribute.version;
}
}
return {
get: get,
remove: remove,
update: update
};
}
export { WebGLAttributes };//使用export语法将WebGLAttributes暴露出来,在其他脚本中可以引入和操作