WebGLã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ãæ¢æ±ãããŠããã©ãŒã ããŒã¿ã®å¹ççã§æ§é åããã管çãç¿åŸããçŸä»£ã®ã°ã©ãã£ãã¯ã¹ã¢ããªã±ãŒã·ã§ã³ã«ãããããã©ãŒãã³ã¹ãšæ§æãåäžãããŸãã
WebGLã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ïŒæ§é åããããŠããã©ãŒã ããŒã¿ç®¡çããã¹ã¿ãŒãã
WebGLã«ãã£ãŠå®çŸããããªã¢ã«ã¿ã€ã 3Dã°ã©ãã£ãã¯ã¹ã®ãã€ãããã¯ãªäžçã§ã¯ãå¹ççãªããŒã¿ç®¡çãæãéèŠã§ããã¢ããªã±ãŒã·ã§ã³ãè€éã«ãªãã«ã€ããŠãããŒã¿ã广çã«æŽçããŠã·ã§ãŒããŒã«æž¡ãå¿ èŠæ§ãå¢å€§ããŸããåŸæ¥ãåå¥ã®ãŠããã©ãŒã ãäž»èŠãªæ¹æ³ã§ãããããããé¢é£ããããŒã¿ã®ã»ããã管çããå Žåãç¹ã«é »ç¹ã«æŽæ°ããå¿ èŠãããå Žåããè€æ°ã®ã·ã§ãŒããŒéã§å ±æããå¿ èŠãããå ŽåãWebGLã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ã¯åŒ·åãã€æŽç·Žããããœãªã¥ãŒã·ã§ã³ãæäŸããŸãããã®èšäºã§ã¯ãã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ã®è€éãããã®å©ç¹ãå®è£ ãããã³WebGLãããžã§ã¯ãã§ããããæŽ»çšããããã®ãã¹ããã©ã¯ãã£ã¹ã«ã€ããŠè©³ãã説æããŸãã
å¿ èŠæ§ã®çè§£ïŒåå¥ã®ãŠããã©ãŒã ã®éç
ãŠããã©ãŒã ãããã¯ã«å ¥ãåã«ãåŸæ¥ã®GãšNãã®å¶éã«ã€ããŠç°¡åã«æ¯ãè¿ããŸããããWebGLã§ã¯ããŠããã©ãŒã ã¯ã¢ããªã±ãŒã·ã§ã³åŽããèšå®ãããåäžã®æç»åŒã³åºãäžã«ã·ã§ãŒããŒããã°ã©ã ã«ãã£ãŠåŠçããããã¹ãŠã®é ç¹ãšãã©ã°ã¡ã³ãã«å¯ŸããŠå®æ°ãšãªã倿°ã§ãããããã¯ãã«ã¡ã©è¡åãã©ã€ãã£ã³ã°ãã©ã¡ãŒã¿ãæéããããªã¢ã«ããããã£ãªã©ã®ãã¬ãŒã ããšã®ããŒã¿ãGPUã«æž¡ãããã«äžå¯æ¬ ã§ãã
åå¥ã®ãŠããã©ãŒã ãèšå®ããåºæ¬çãªã¯ãŒã¯ãããŒã¯æ¬¡ã®ãšããã§ãã
gl.getUniformLocation()ã䜿çšããŠãŠããã©ãŒã 倿°ã®å ŽæãååŸããŸããgl.uniform1f()ãgl.uniformMatrix4fv()ãªã©ã®é¢æ°ã䜿çšããŠãŠããã©ãŒã ã®å€ãèšå®ããŸãã
ãã®æ¹æ³ã¯åçŽã§å°æ°ã®ãŠããã©ãŒã ã«ã¯ããŸãæ©èœããŸãããè€éããå¢ããšããã€ãã®èª²é¡ãçããŸãã
- ããã©ãŒãã³ã¹ãªãŒããŒãããïŒ
gl.getUniformLocation()ããã³ããã«ç¶ãgl.uniform*()颿°ãžã®é »ç¹ãªåŒã³åºãã¯ãç¹ã«å€ãã®ãŠããã©ãŒã ãç¹°ãè¿ãæŽæ°ããå Žåã«CPUãªãŒããŒããããåŒãèµ·ããå¯èœæ§ããããŸããååŒã³åºãã«ã¯CPUãšGPUéã®åŸåŸ©ãçºçããŸãã - ã³ãŒãã®æ£ä¹±ïŒ æ°åãŸãã¯æ°çŸã®åå¥ã®ãŠããã©ãŒã ã管çãããšãåé·ã§ä¿å®ãå°é£ãªã·ã§ãŒããŒã³ãŒãããã³ã¢ããªã±ãŒã·ã§ã³ããžãã¯ã«ã€ãªããå¯èœæ§ããããŸãã
- ããŒã¿ã®åé·æ§ïŒ ãŠããã©ãŒã ã®ã»ãããè«ççã«é¢é£ããŠããå ŽåïŒäŸïŒå æºã®ãã¹ãŠã®ããããã£ïŒããããã¯ãŠããã©ãŒã 宣èšãªã¹ãå šäœã«æ£ãã°ã£ãŠããããšãå€ãããããã®éåçãªæå³ãææ¡ããã®ãé£ãããªããŸãã
- éå¹çãªæŽæ°ïŒ å€§èŠæš¡ã§æ§é åãããŠããªããŠããã©ãŒã ã»ããã®ããäžéšãæŽæ°ããã ãã§ããããªãã®éã®ããŒã¿ãéä¿¡ããå¿ èŠãããå ŽåããããŸãã
ã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ã®å°å ¥ïŒæ§é åãããã¢ãããŒã
ã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ã¯ãOpenGLã§ã¯ãŠããã©ãŒã ãããã¡ãªããžã§ã¯ãïŒUBOïŒãšãåŒã°ããWebGLã§ãæŠå¿µçã«äŒŒãŠããŸãããé¢é£ãããŠããã©ãŒã 倿°ãåäžã®ãããã¯ã«ã°ã«ãŒãåããããšã§ãããã®å¶éã«å¯ŸåŠããŸãããã®ãããã¯ã¯ãããã¡ãªããžã§ã¯ãã«ãã€ã³ãã§ãããã®ãããã¡ã¯è€æ°ã®ã·ã§ãŒããŒããã°ã©ã éã§å ±æã§ããŸãã
æ žãšãªãã¢ã€ãã¢ã¯ãäžé£ã®ãŠããã©ãŒã ãGPUäžã®é£ç¶ããã¡ã¢ãªãããã¯ãšããŠæ±ãããšã§ãããŠããã©ãŒã ãããã¯ãå®çŸ©ããéããã®ã¡ã³ããŒïŒåã ã®ãŠããã©ãŒã 倿°ïŒããããã¯å ã§å®£èšããŸãããã®æ§é ã«ãããWebGLãã©ã€ããŒã¯ã¡ã¢ãªã¬ã€ã¢ãŠããšããŒã¿è»¢éãæé©åã§ããŸãã
ã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ã®äž»èŠãªæŠå¿µïŒ
- ãããã¯å®çŸ©ïŒ GLSLïŒOpenGL Shading LanguageïŒã§ã¯ã
uniform blockæ§æã䜿çšããŠãŠããã©ãŒã ãããã¯ãå®çŸ©ããŸãã - ãã€ã³ãã£ã³ã°ãã€ã³ãïŒ ãŠããã©ãŒã ãããã¯ã¯ãWebGL APIã«ãã£ãŠç®¡çãããç¹å®ã®ãã€ã³ãã£ã³ã°ãã€ã³ãïŒã€ã³ããã¯ã¹ïŒã«é¢é£ä»ããããŸãã
- ãããã¡ãªããžã§ã¯ãïŒ
WebGLBufferã¯ãŠããã©ãŒã ãããã¯ã®å®éã®ããŒã¿ãæ ŒçŽããããã«äœ¿çšãããŸãããã®ãããã¡ã¯ããŠããã©ãŒã ãããã¯ã®ãã€ã³ãã£ã³ã°ãã€ã³ãã«ãã€ã³ããããŸãã - ã¬ã€ã¢ãŠã修食åïŒãªãã·ã§ã³ã§ããæšå¥šïŒïŒ GLSLã§ã¯ã
std140ãstd430ãªã©ã®ã¬ã€ã¢ãŠã修食åã䜿çšããŠããããã¯å ã®ãŠããã©ãŒã ã®ã¡ã¢ãªã¬ã€ã¢ãŠããæå®ã§ããŸããããã¯ãç°ãªãGLSLããŒãžã§ã³ãããŒããŠã§ã¢éã§äºæž¬å¯èœãªã¡ã¢ãªé 眮ãä¿èšŒããããã«éèŠã§ãã
WebGLã§ã®ã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ã®å®è£
ãŠããã©ãŒã ãããã¯ã®å®è£ ã«ã¯ãGLSLã·ã§ãŒããŒãšJavaScriptã¢ããªã±ãŒã·ã§ã³ã³ãŒãã®äž¡æ¹ã®å€æŽãå¿ èŠã§ãã
1. GLSLã·ã§ãŒããŒã³ãŒã
GLSLã·ã§ãŒããŒã§ãŠããã©ãŒã ãããã¯ã次ã®ããã«å®çŸ©ããŸãã
uniform PerFrameUniforms {
mat4 projectionMatrix;
mat4 viewMatrix;
vec3 cameraPosition;
float time;
} perFrame;
ãã®äŸã§ã¯ïŒ
uniform PerFrameUniformsã¯ãPerFrameUniformsãšããååã®ãŠããã©ãŒã ãããã¯ã宣èšããŸãã- ãããã¯å
ã§ã
projectionMatrixãviewMatrixãcameraPositionãtimeãšããåå¥ã®ãŠããã©ãŒã 倿°ã宣èšããŸãã perFrameã¯ãã®ãããã¯ã®ã€ã³ã¹ã¿ã³ã¹åã§ããããã®ã¡ã³ããŒãåç §ã§ããŸãïŒäŸïŒperFrame.projectionMatrixïŒã
ã¬ã€ã¢ãŠã修食åã®äœ¿çšïŒ
äžè²«ããã¡ã¢ãªã¬ã€ã¢ãŠãã確ä¿ããããã«ãã¬ã€ã¢ãŠã修食åã®äœ¿çšã匷ããå§ãããŸããæãäžè¬çãªãã®ã¯ std140 ãš std430 ã§ãã
std140ïŒããã¯ãŠããã©ãŒã ãããã¯ã®ããã©ã«ãã®ã¬ã€ã¢ãŠãã§ãããéåžžã«äºæž¬å¯èœã§ãããæãšããŠã¡ã¢ãªå¹çãæªãã¬ã€ã¢ãŠããæäŸããŸããäžè¬çã«å®å šã§ãã»ãšãã©ã®ãã©ãããã©ãŒã ã§æ©èœããŸããstd430ïŒãã®ã¬ã€ã¢ãŠãã¯ããæè»ã§ãç¹ã«é åã«ãããŠã¡ã¢ãªå¹çãè¯ãå ŽåããããŸãããGLSLããŒãžã§ã³ã®ãµããŒãã«é¢ããŠããå³ããèŠä»¶ããããããããŸããã
以äžã¯ std140 ã䜿çšããäŸã§ãã
// Specify the layout qualifier for the uniform block
layout(std140) uniform PerFrameUniforms {
mat4 projectionMatrix;
mat4 viewMatrix;
vec3 cameraPosition;
float time;
} perFrame;
ã¡ã³ããŒåœåã«é¢ããéèŠãªæ³šæïŒ ãããã¯å ã®ãŠããã©ãŒã ã¯ããã®ååãä»ããŠã¢ã¯ã»ã¹ã§ããŸããã¢ããªã±ãŒã·ã§ã³ã³ãŒãã¯ããããã¯å ã®ãããã®ã¡ã³ããŒã®äœçœ®ãç §äŒããå¿ èŠããããŸãã
2. JavaScriptã¢ããªã±ãŒã·ã§ã³ã³ãŒã
JavaScriptåŽã§ã¯ããŠããã©ãŒã ãããã¯ãèšå®ããã³ç®¡çããããã«ããã€ãã®è¿œå ã¹ããããå¿ èŠã§ãã
a. ã·ã§ãŒããŒããã°ã©ã ã®ãªã³ã¯ãšãããã¯ã€ã³ããã¯ã¹ã®ç §äŒ
ãŸããã·ã§ãŒããŒãããã°ã©ã ã«ãªã³ã¯ããå®çŸ©ãããŠããã©ãŒã ãããã¯ã®ã€ã³ããã¯ã¹ãç §äŒããŸãã
// Assuming you have already created and linked your WebGL program
const program = gl.createProgram();
// ... attach shaders, link program ...
// Get the uniform block index
const blockIndex = gl.getUniformBlockIndex(program, 'PerFrameUniforms');
if (blockIndex === gl.INVALID_INDEX) {
console.warn('Uniform block PerFrameUniforms not found.');
} else {
// Query the active uniform block parameters
const blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
const uniformCount = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS);
const uniformIndices = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES);
console.log(`Uniform block PerFrameUniforms found:`);
console.log(` Size: ${blockSize} bytes`);
console.log(` Active Uniforms: ${uniformCount}`);
// Get names of uniforms within the block
const uniformNames = [];
for (let i = 0; i < uniformIndices.length; i++) {
const uniformInfo = gl.getActiveUniform(program, uniformIndices[i]);
uniformNames.push(uniformInfo.name);
}
console.log(` Uniforms: ${uniformNames.join(', ')}`);
// Get the binding point for this uniform block
// This is crucial for binding the buffer later
gl.uniformBlockBinding(program, blockIndex, blockIndex); // Using blockIndex as binding point for simplicity
}
b. ãããã¡ãªããžã§ã¯ãã®äœæãšããŒã¿å ¥å
次ã«ããŠããã©ãŒã ãããã¯ã®ããŒã¿ãä¿æããããã® WebGLBuffer ãäœæããå¿
èŠããããŸãããã®ãããã¡ã®ãµã€ãºã¯ã以åã«ååŸãã UNIFORM_BLOCK_DATA_SIZE ãšäžèŽããå¿
èŠããããŸãããã®åŸããã®ãããã¡ã«ãŠããã©ãŒã ã®å®éã®ããŒã¿ãå
¥åããŸãã
ããŒã¿ãªãã»ããã®èšç®ïŒ
ããã§ã®èª²é¡ã¯ããããã¯å
ã®ãŠããã©ãŒã ã¯é£ç¶ããŠé
眮ãããŸãããå¿
ãããå¯ã«ããã¯ãããŠããããã§ã¯ãªãããšã§ãããã©ã€ããŒã¯ãã¬ã€ã¢ãŠã修食åïŒstd140 ãŸã㯠std430ïŒã«åºã¥ããŠåã¡ã³ããŒã®æ£ç¢ºãªãªãã»ãããšã¢ã©ã€ã¡ã³ããæ±ºå®ããŸããããŒã¿ãæ£ããæžã蟌ãã«ã¯ããããã®ãªãã»ãããç
§äŒããå¿
èŠããããŸãã
WebGLã¯ãããã°ã©ã å
ã®åã
ã®ãŠããã©ãŒã ã®ã€ã³ããã¯ã¹ãååŸããããã« gl.getUniformIndices() ãæäŸãããã®åŸãããã®ãªãã»ãããå«ãæ
å ±ã«ã€ããŠã¯ gl.getActiveUniforms() ãæäŸããŸãã
// Assuming blockIndex is valid
// Get indices of individual uniforms within the block
const uniformIndices = gl.getUniformIndices(program, ['projectionMatrix', 'viewMatrix', 'cameraPosition', 'time']);
// Get offsets and sizes of each uniform
const offsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
const sizes = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_SIZE);
const types = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_TYPE);
// Map uniform names to their offsets and sizes for easier access
const uniformInfoMap = {};
uniformIndices.forEach((index, i) => {
const uniformName = gl.getActiveUniform(program, index).name;
uniformInfoMap[uniformName] = {
offset: offsets[i],
size: sizes[i], // For arrays, this is the number of elements
type: types[i]
};
});
console.log('Uniform offsets and sizes:', uniformInfoMap);
// --- Data Packing ---
// This is the most complex part. You need to pack your data according to std140/std430 rules.
// Let's assume we have our matrices and vectors ready:
const projectionMatrix = new Float32Array([...]); // 16 elements
const viewMatrix = new Float32Array([...]); // 16 elements
const cameraPosition = new Float32Array([x, y, z, 0.0]); // vec3 is often padded to 4 components
const time = 0.5;
// Create a typed array to hold the packed data. Its size must match blockSize.
const bufferData = new ArrayBuffer(blockSize); // Use blockSize obtained earlier
const dataView = new DataView(bufferData);
// Pack data based on offsets and types (simplified example, actual packing requires careful handling of types and alignment)
// Packing mat4 (std140: 4 vec4 components, each 16 bytes. Total 64 bytes per mat4)
// Each mat4 is effectively 4 vec4s in std140.
// projectionMatrix
const projMatrixInfo = uniformInfoMap['projectionMatrix'];
if (projMatrixInfo) {
const mat4Bytes = 16 * 4; // 4 rows * 4 components per row, 4 bytes per component
let offset = projMatrixInfo.offset;
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 4; col++) {
dataView.setFloat32(offset + (row * 4 + col) * 4, projectionMatrix[row * 4 + col], true);
}
}
}
// viewMatrix (similar packing)
const viewMatrixInfo = uniformInfoMap['viewMatrix'];
if (viewMatrixInfo) {
const mat4Bytes = 16 * 4;
let offset = viewMatrixInfo.offset;
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 4; col++) {
dataView.setFloat32(offset + (row * 4 + col) * 4, viewMatrix[row * 4 + col], true);
}
}
}
// cameraPosition (vec3 often packed as vec4 in std140)
const camPosInfo = uniformInfoMap['cameraPosition'];
if (camPosInfo) {
dataView.setFloat32(camPosInfo.offset, cameraPosition[0], true);
dataView.setFloat32(camPosInfo.offset + 4, cameraPosition[1], true);
dataView.setFloat32(camPosInfo.offset + 8, cameraPosition[2], true);
dataView.setFloat32(camPosInfo.offset + 12, 0.0, true); // Padding
}
// time (float)
const timeInfo = uniformInfoMap['time'];
if (timeInfo) {
dataView.setFloat32(timeInfo.offset, time, true);
}
// --- Create and Bind Buffer ---
const uniformBuffer = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, uniformBuffer);
gl.bufferData(gl.UNIFORM_BUFFER, bufferData, gl.DYNAMIC_DRAW); // Or gl.STATIC_DRAW if data doesn't change
// Bind the buffer to the uniform block's binding point
// Use the binding point that was set with gl.uniformBlockBinding earlier
// In our example, we used blockIndex as the binding point.
const bindingPoint = blockIndex;
gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, uniformBuffer);
c. ãŠããã©ãŒã ãããã¯ããŒã¿ã®æŽæ°
ããŒã¿ãæŽæ°ãããå¿
èŠãããå ŽåïŒäŸïŒã«ã¡ã©ã®ç§»åãæéã®çµéïŒãããŒã¿ã bufferData ã«åããã¯ããéšåçãªæŽæ°ã«ã¯ gl.bufferSubData() ã䜿çšããŠGPUäžã®ãããã¡ãæŽæ°ããããå®å
šãªçœ®ãæãã«ã¯ gl.bufferData() ã䜿çšããŸãã
// Assuming uniformBuffer, bufferData, dataView, and uniformInfoMap are accessible
// Update your data variables...
const newTime = performance.now() / 1000.0;
const updatedCameraPosition = [...currentCamera.position.toArray(), 0.0];
// Re-pack only changed data for efficiency
const timeInfo = uniformInfoMap['time'];
if (timeInfo) {
dataView.setFloat32(timeInfo.offset, newTime, true);
}
const camPosInfo = uniformInfoMap['cameraPosition'];
if (camPosInfo) {
dataView.setFloat32(camPosInfo.offset, updatedCameraPosition[0], true);
dataView.setFloat32(camPosInfo.offset + 4, updatedCameraPosition[1], true);
dataView.setFloat32(camPosInfo.offset + 8, updatedCameraPosition[2], true);
dataView.setFloat32(camPosInfo.offset + 12, 0.0, true); // Padding
}
// Update the buffer on the GPU
gl.bindBuffer(gl.UNIFORM_BUFFER, uniformBuffer);
gl.bufferSubData(gl.UNIFORM_BUFFER, 0, bufferData); // Update the entire buffer, or specify offsets
d. ãŠããã©ãŒã ãããã¯ã®ã·ã§ãŒããŒãžã®ãã€ã³ãã£ã³ã°
æç»ããåã«ããŠããã©ãŒã ãããã¯ãããã°ã©ã ã«æ£ãããã€ã³ããããŠããããšã確èªããå¿ èŠããããŸããããã¯éåžžãããã°ã©ã ããšã«1åããŸãã¯åããŠããã©ãŒã ãããã¯å®çŸ©ã䜿çšããããã€ã³ãã£ã³ã°ãã€ã³ããç°ãªãå¯èœæ§ã®ããããã°ã©ã éãåãæ¿ãããšãã«å®è¡ãããŸãã
ããã§ã®äž»èŠãªé¢æ°ã¯ gl.uniformBlockBinding(program, blockIndex, bindingPoint); ã§ããããã¯ãæå®ããã program å
ã§ blockIndex ã«ãã£ãŠèå¥ããããŠããã©ãŒã ãããã¯ã«ã©ã® bindingPoint ã«ãã€ã³ãããããããã¡ã䜿çšãã¹ãããWebGLãã©ã€ããŒã«äŒããŸãã
è€æ°ã®ããã°ã©ã éã§ç°ãªããã€ã³ãã£ã³ã°ãã€ã³ããå¿
èŠãšãããŠããã©ãŒã ãããã¯ãå
±æããªãå Žåã¯ãç°¡çŽ åã®ããã« blockIndex èªäœã bindingPoint ãšããŠäœ¿çšããã®ãäžè¬çã§ãã
// During program setup or when switching programs:
const blockIndex = gl.getUniformBlockIndex(program, 'PerFrameUniforms');
const bindingPoint = blockIndex; // Or any other desired binding point index (0-15 typically)
if (blockIndex !== gl.INVALID_INDEX) {
gl.uniformBlockBinding(program, blockIndex, bindingPoint);
// Later, when binding buffers:
// gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, yourUniformBuffer);
}
3. ã·ã§ãŒããŒéã§ã®ãŠããã©ãŒã ãããã¯ã®å ±æ
ãŠããã©ãŒã ãããã¯ã®æãéèŠãªå©ç¹ã®1ã€ã¯ãããããå ±æå¯èœã§ããããšã§ãããŸã£ããåãååãšã¡ã³ããŒæ§é ïŒé åºãšåãå«ãïŒã§ãŠããã©ãŒã ãããã¯ãå®çŸ©ããè€æ°ã®ã·ã§ãŒããŒããã°ã©ã ãããå Žåããã¹ãŠã®ãããã®ããã°ã©ã ã«å¯ŸããŠåããããã¡ãªããžã§ã¯ããåããã€ã³ãã£ã³ã°ãã€ã³ãã«ãã€ã³ãã§ããŸãã
䜿çšäŸïŒ
ç°ãªãã·ã§ãŒããŒïŒäŸïŒäžéšã«ã¯Phongã·ã§ãŒããŒãä»ã«ã¯PBRã·ã§ãŒããŒïŒã䜿çšããŠè€æ°ã®ãªããžã§ã¯ããã¬ã³ããªã³ã°ãããã·ãŒã³ãæ³åããŠãã ãããäž¡æ¹ã®ã·ã§ãŒããŒããã¬ãŒã ããšã®ã«ã¡ã©ããã³ã©ã€ãã£ã³ã°æ
å ±ãå¿
èŠãšããå ŽåããããŸããããããã«åå¥ã®ãŠããã©ãŒã ãããã¯ãå®çŸ©ãã代ããã«ãäž¡æ¹ã®GLSLãã¡ã€ã«ã§å
±éã® PerFrameUniforms ãããã¯ãå®çŸ©ã§ããŸãã
- ã·ã§ãŒããŒA (Phong)ïŒ
layout(std140) uniform PerFrameUniforms { mat4 projectionMatrix; mat4 viewMatrix; vec3 cameraPosition; float time; } perFrame; void main() { // ... Phong lighting calculations ... } - ã·ã§ãŒããŒB (PBR)ïŒ
layout(std140) uniform PerFrameUniforms { mat4 projectionMatrix; mat4 viewMatrix; vec3 cameraPosition; float time; } perFrame; void main() { // ... PBR rendering calculations ... }
JavaScriptã§ã¯ãæ¬¡ã®æé ãå®è¡ããŸãã
- ã·ã§ãŒããŒAã®ããã°ã©ã ã§
PerFrameUniformsã®blockIndexãååŸããŸãã gl.uniformBlockBinding(programA, blockIndexA, bindingPoint);ãåŒã³åºããŸãã- ã·ã§ãŒããŒBã®ããã°ã©ã ã§
PerFrameUniformsã®blockIndexãååŸããŸãã gl.uniformBlockBinding(programB, blockIndexB, bindingPoint);ãåŒã³åºããŸããbindingPointãäž¡æ¹ã§åãã§ããããšãéèŠã§ããPerFrameUniformsçšã«1ã€ã®WebGLBufferãäœæããŸãã- ã·ã§ãŒããŒAãŸãã¯ã·ã§ãŒããŒBã®ããããã§æç»ããåã«ã
gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, yourSingleUniformBuffer);ã䜿çšããŠãã®ãããã¡ã«ããŒã¿ãå ¥åãããã€ã³ãããŸãã
ãã®ã¢ãããŒãã«ãããè€æ°ã®ã·ã§ãŒããŒãåããã©ã¡ãŒã¿ã»ãããå ±æããå Žåã®åé·ãªããŒã¿è»¢éãå€§å¹ ã«åæžããããŠããã©ãŒã 管çãç°¡çŽ åãããŸãã
ã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ã䜿çšããå©ç¹
ãŠããã©ãŒã ãããã¯ã掻çšãããšã倧ããªå©ç¹ãåŸãããŸãã
- ããã©ãŒãã³ã¹ã®åäžïŒ åå¥ã®APIåŒã³åºãã®æ°ãæžããããã©ã€ããŒãããŒã¿ã¬ã€ã¢ãŠããæé©åã§ããããã«ããããšã§ããŠããã©ãŒã ãããã¯ã¯ããé«éãªã¬ã³ããªã³ã°ã«ã€ãªãããŸããæŽæ°ã¯ãããåŠçã§ããGPUã¯ããŒã¿ã«å¹ççã«ã¢ã¯ã»ã¹ã§ããŸãã
- çµç¹åã®åŒ·åïŒ è«ççã«é¢é£ãããŠããã©ãŒã ããããã¯ã«ã°ã«ãŒãåããããšã§ãã·ã§ãŒããŒã³ãŒããããã¯ãªãŒã³ã§èªã¿ããããªããŸããGPUã«æž¡ãããããŒã¿ã®å 容ãçè§£ãããããªããŸãã
- CPUãªãŒããŒãããã®åæžïŒ
gl.getUniformLocation()ããã³gl.uniform*()ãžã®åŒã³åºããæžãããšã§ãCPUã®è² è·ã軜æžãããŸãã - ããŒã¿å ±æïŒ åäžã®ãããã¡ãåããã€ã³ãã£ã³ã°ãã€ã³ãã§è€æ°ã®ã·ã§ãŒããŒããã°ã©ã ã«ãã€ã³ãã§ããæ©èœã¯ãã³ãŒãã®åå©çšãšããŒã¿å¹çã«ãšã£ãŠåŒ·åãªæ©èœã§ãã
- ã¡ã¢ãªå¹çïŒ ç¹ã«
std430ã䜿çšããæ éãªãããã³ã°ã«ããããŠããã©ãŒã ãããã¯ã¯GPUäžã§ããã³ã³ãã¯ããªããŒã¿ã¹ãã¬ãŒãžã«ã€ãªããå¯èœæ§ããããŸãã
ãã¹ããã©ã¯ãã£ã¹ãšèæ ®äºé
ãŠããã©ãŒã ãããã¯ãæå€§éã«æŽ»çšããããã«ã以äžã®ãã¹ããã©ã¯ãã£ã¹ãèæ ®ããŠãã ããã
- äžè²«ããã¬ã€ã¢ãŠãã®äœ¿çšïŒ GLSLã·ã§ãŒããŒã§ã¯åžžã«ã¬ã€ã¢ãŠã修食åïŒ
std140ãŸãã¯std430ïŒã䜿çšããJavaScriptã§ã®ããŒã¿ãããã³ã°ãšäžèŽããŠããããšã確èªããŠãã ãããstd140ã¯å¹ åºãäºææ§ã®ããã«ããå®å šã§ãã - ã¡ã¢ãªã¬ã€ã¢ãŠãã®çè§£ïŒ éžæããã¬ã€ã¢ãŠãã«åŸã£ãŠãç°ãªãGLSLåïŒã¹ã«ã©ãŒããã¯ãã«ãè¡åãé åïŒãã©ã®ããã«ããã¯ãããããçè§£ããŠãã ãããããã¯æ£ããããŒã¿é 眮ã®ããã«éèŠã§ããOpenGL ESã®ä»æ§æžãGLSLã¬ã€ã¢ãŠãã«é¢ãããªã³ã©ã€ã³ã¬ã€ãã®ãããªãªãœãŒã¹ã¯éåžžã«è²Žéã§ãã
- ãªãã»ãããšãµã€ãºã®ç
§äŒïŒ ãªãã»ãããããŒãã³ãŒãããªãã§ãã ãããã¢ããªã±ãŒã·ã§ã³ãç°ãªãGLSLããŒãžã§ã³ãããŒããŠã§ã¢ãšäºææ§ãããããšã確èªããããã«ãåžžã«WebGL APIïŒ
gl.UNIFORM_OFFSETã䜿çšããgl.getActiveUniforms()ïŒã䜿çšããŠãªãã»ãããç §äŒããŠãã ããã - å¹ççãªæŽæ°ïŒ
gl.bufferData()ã§ãããã¡å šäœãåã¢ããããŒãããã®ã§ã¯ãªããgl.bufferSubData()ã䜿çšããŠå€æŽãããéšåã®ã¿ãæŽæ°ããŠãã ãããããã¯éèŠãªããã©ãŒãã³ã¹æé©åã§ãã - ãããã¯ãã€ã³ãã£ã³ã°ãã€ã³ãïŒ ãã€ã³ãã£ã³ã°ãã€ã³ãã®å²ãåœãŠã«ã¯äžè²«ããæŠç¥ã䜿çšããŠãã ãããå€ãã®å ŽåããŠããã©ãŒã ãããã¯ã€ã³ããã¯ã¹èªäœããã€ã³ãã£ã³ã°ãã€ã³ããšããŠäœ¿çšã§ããŸãããç°ãªãUBOã€ã³ããã¯ã¹ã§ãåããããã¯å/ã¬ã€ã¢ãŠããæã€ããã°ã©ã éã§å ±æããå Žåã¯ãå ±éã®æç€ºçãªãã€ã³ãã£ã³ã°ãã€ã³ããå²ãåœãŠãå¿ èŠããããŸãã
- ãšã©ãŒãã§ãã¯ïŒ ãŠããã©ãŒã ãããã¯ã€ã³ããã¯ã¹ãååŸããéã¯ãåžžã«
gl.INVALID_INDEXããã§ãã¯ããŠãã ããããŠããã©ãŒã ãããã¯ã®åé¡ã®ãããã°ã¯æãšããŠå°é£ã§ããããã现å¿ã®æ³šæãæã£ããšã©ãŒãã§ãã¯ãäžå¯æ¬ ã§ãã - ããŒã¿åã®ã¢ã©ã€ã¡ã³ãïŒ ããŒã¿åã®ã¢ã©ã€ã¡ã³ãã«çްå¿ã®æ³šæãæã£ãŠãã ãããäŸãã°ã
vec3ã¯ã¡ã¢ãªå ã§vec4ã«ããã£ã³ã°ãããå ŽåããããŸããJavaScriptã®ãããã³ã°ããã®ããã£ã³ã°ãèæ ®ããŠããããšã確èªããŠãã ããã - ã°ããŒãã«ããŒã¿ vs. ãªããžã§ã¯ãããšã®ããŒã¿ïŒ æç»åŒã³åºããŸãã¯æç»åŒã³åºãã®ã°ã«ãŒãå šäœã§åäžãªããŒã¿ïŒäŸïŒãã¬ãŒã ããšã®ã«ã¡ã©ãã·ãŒã³ã©ã€ãã£ã³ã°ïŒã«ã¯ãŠããã©ãŒã ãããã¯ã䜿çšããŸãããªããžã§ã¯ãããšã®ããŒã¿ã«ã¯ãå¿ èŠã«å¿ããŠã€ã³ã¹ã¿ã³ã¹åãé ç¹å±æ§ã®ãããªä»ã®ã¡ã«ããºã ãæ€èšããŠãã ããã
äžè¬çãªåé¡ã®ãã©ãã«ã·ã¥ãŒãã£ã³ã°
ãŠããã©ãŒã ãããã¯ã䜿çšããéã«ã次ã®åé¡ã«ééããå¯èœæ§ããããŸãã
- ãŠããã©ãŒã ãããã¯ãèŠã€ãããªãïŒ GLSLã®ãŠããã©ãŒã ãããã¯åã
gl.getUniformBlockIndex()ã§äœ¿çšãããŠããååãšå®å šã«äžèŽããŠãããå確èªããŠãã ãããã¯ãšãªå®è¡æã«ã¯ã·ã§ãŒããŒããã°ã©ã ãã¢ã¯ãã£ãã§ããããšã確èªããŠãã ããã - 誀ã£ãããŒã¿ã衚瀺ãããïŒ ããã¯ã»ãŒåžžã«äžé©åãªããŒã¿ãããã³ã°ãåå ã§ããGLSLã¬ã€ã¢ãŠãèŠåã«å¯ŸããŠãªãã»ãããããŒã¿åãã¢ã©ã€ã¡ã³ãã確èªããŠãã ããã`WebGL Inspector` ãåæ§ã®ãã©ãŠã¶éçºè ããŒã«ãããããã¡ã®å 容ãèŠèŠåããã®ã«åœ¹ç«ã€å ŽåããããŸãã
- ã¯ã©ãã·ã¥ãŸãã¯ã°ãªããïŒ å€ãã®å Žåããããã¡ãµã€ãºã®äžäžèŽïŒãããã¡ãå°ããããïŒãŸãã¯èª€ã£ããã€ã³ãã£ã³ã°ãã€ã³ãã®å²ãåœãŠãåå ã§ãã
gl.bufferData()ãæ£ããUNIFORM_BLOCK_DATA_SIZEã䜿çšããŠããããšã確èªããŠãã ããã - å
±æã®åé¡ïŒ ããã·ã§ãŒããŒã§ã¯ãŠããã©ãŒã ãããã¯ãæ©èœããããå¥ã®ã·ã§ãŒããŒã§ã¯æ©èœããªãå Žåãäž¡æ¹ã®GLSLãã¡ã€ã«ã§ãããã¯å®çŸ©ïŒååãã¡ã³ããŒãã¬ã€ã¢ãŠãïŒãåäžã§ããããšã確èªããŠãã ããããŸãã
gl.uniformBlockBinding()ãä»ããŠãåããã€ã³ãã£ã³ã°ãã€ã³ãã䜿çšãããåããã°ã©ã ã«æ£ããé¢é£ä»ããããŠããããšã確èªããŠãã ããã
åºæ¬çãªãŠããã©ãŒã ãè¶ ããŠïŒé«åºŠãªäœ¿çšäŸ
ã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ã¯ãåçŽãªãã¬ãŒã ããšã®ããŒã¿ã«éå®ãããŸãããããè€éãªã·ããªãªã§äœ¿çšã§ããŸãã
- ãããªã¢ã«ããããã£ïŒ ãããªã¢ã«ã«é¢ãããã¹ãŠã®ãã©ã¡ãŒã¿ïŒäŸïŒæ¡æ£è²ãã¹ããã¥ã©åŒ·åºŠãå æ²¢ããã¯ã¹ãã£ãµã³ãã©ãŒïŒããŠããã©ãŒã ãããã¯ã«ã°ã«ãŒãåããŸãã
- ã©ã€ãé
åïŒ å€æ°ã®ã©ã€ããããå ŽåããŠããã©ãŒã ãããã¯å
ã«ã©ã€ãæ§é ã®é
åãå®çŸ©ã§ããŸããããã¯ãé
åã«å¯Ÿãã
std430ã¬ã€ã¢ãŠãã®çè§£ãç¹ã«éèŠã«ãªãéšåã§ãã - ã¢ãã¡ãŒã·ã§ã³ããŒã¿ïŒ ã¹ã±ã«ãã³ã¢ãã¡ãŒã·ã§ã³ã®ããŒãã¬ãŒã ããŒã¿ãããŒã³å€æãæž¡ããŸãã
- ã°ããŒãã«ã·ãŒã³èšå®ïŒ ãã©ã°ãã©ã¡ãŒã¿ãå€§æ°æ£ä¹±ä¿æ°ãã°ããŒãã«ã«ã©ãŒã°ã¬ãŒãã£ã³ã°èª¿æŽãªã©ã®ç°å¢ããããã£ã
çµè«
WebGLã·ã§ãŒããŒãŠããã©ãŒã ãããã¯ïŒãŸãã¯ãŠããã©ãŒã ãããã¡ãªããžã§ã¯ãïŒã¯ãçŸä»£çã§é«æ§èœãªWebGLã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠäžå¯æ¬ ãªããŒã«ã§ããåå¥ã®ãŠããã©ãŒã ããæ§é åããããããã¯ãžç§»è¡ããããšã§ãéçºè ã¯ã³ãŒãã®æ§æãä¿å®æ§ãã¬ã³ããªã³ã°é床ã«ãããŠå€§å¹ ãªæ¹åãéæã§ããŸããåæèšå®ãç¹ã«ããŒã¿ãããã³ã°ã¯è€éã«æãããããããŸããããå€§èŠæš¡ãªã°ã©ãã£ãã¯ã¹ãããžã§ã¯ãã管çããäžã§ã®é·æçãªå©ç¹ã¯åŠå®ã§ããŸããããã®ãã¯ããã¯ãç¿åŸããããšã¯ããŠã§ãããŒã¹ã®3Dã°ã©ãã£ãã¯ã¹ãšã€ã³ã¿ã©ã¯ãã£ããªäœéšã®éçãæŒãåºããããšãããã¹ãŠã®äººã«ãšã£ãŠäžå¯æ¬ ã§ãã
æ§é åããããŠããã©ãŒã ããŒã¿ç®¡çãåãå ¥ããããšã§ããŠã§ãäžã§ããè€éã§å¹ççããããŠèŠèŠçã«çŽ æŽãããã¢ããªã±ãŒã·ã§ã³ãžã®éãéãããŸãã