서두에
[이전 노트](/articles/마우스 클릭 위치에 점 그리기-webgl 노트 3/) 에서, 우리는 attribute 변수를 통해 마우스 클릭 위치의 좌표 정보를 정점 셰이더에 전달하여, 클릭한 위치에 점을 그리는 효과를 실현했지만, 그려진 점은 모두 같은 색상이었습니다. 점의 색상을 동적으로 설정하고 싶다면, uniform 변수가 필요합니다. 왜냐하면attribute 변수는 정점 셰이더에서만 사용 가능하고, 색상 정보는 단편 셰이더 중에 있기 때문입니다
一.uniform 변수와 attribute 변수
uniform 과 attribute 는 유사하며, 둘 다 저장 한정자입니다. 주요 차이는 다음과 같습니다:
- attribute
정점 셰이더에서만 사용 가능. 정점마다의 데이터 (각 정점에서 이 값이 다름) 를 나타내는 데 사용. 예를 들어 앞에서 사용한 attribute vec4 a_Position
- uniform
정점 셰이더에서도 단편 셰이더에서도 사용 가능. 일관된, 불변의 데이터 (각 정점에서 이 값이 같음) 를 나타내는 데 사용. 예를 들어 향후 텍스처 매핑에서 사용할 uniform Sampler2D u_Sampler, 및 우리가 곧 사용할 uniform vec4 u_FragColor
P.S. uniform 과 attribute 에는 其它의 차이도 있으며, 또 하나의 저장 한정자는 varying 입니다. 이러한 내용은 모두 GLSL ES 구문 노트에서 전개합니다
二.점의 색상 설정
좌표 설정과 유사하게, 먼저 uniform 변수를 선언하여 색상 데이터를 받고, 다음에 색상을 전달하여 그립니다
###1.단편 셰이더
색상 지정 프로세스는 단편 셰이더 중에 있습니다. 단편 셰이더 소스 프로그램을 수정해야 합니다:
// 단편 셰이더 소스 프로그램
//!!! 부동 소수점 정밀도를 선언해야 합니다.否则 오류 No precision specified for (float) 가 보고됩니다
var fsSrc = 'precision mediump float;' +
'uniform vec4 u_FragColor;' +
'void main() {' +
'gl_FragColor = u_FragColor;' + // 색상 설정
'}';
용법은 attribute 변수와 완전히 일치하지만, 특히 주의해야 할 점이 하나 있습니다: 부동 소수점 정밀도를 선언해야 합니다.否则 단편 셰이더는 컴파일에 실패하고, 다음과 같은 오류를 보고합니다:
ERROR: 0:1: '' : No precision specified for (float)
###2.색상 설정
gl.getAttribLocation 과 gl.vertexAttrib3f 와 유사하게, 여기서는 gl.getUniformLocation 와 gl.uniform4f 를 사용합니다:
// 색상 설정
// uniform 변수의 저장 위치를 획득
var u_FragColor = gl.getUniformLocation(glUtil.program, 'u_FragColor');
var color = item.color;
// 색상 값을 uniform 변수에 전달
gl.uniform4f(u_FragColor, color.r, color.g, color.b, color.a);
색상 값 rgba 는 모두 0.0~1.0 임에 주의. 이 구간에 없는 수치는 자동으로 0.0 또는 1.0 으로 절단되지만, 오류는 발생하지 않습니다
###3.여러 점 그리기
여기서는 직접 gl.drawArrays(gl.POINTS, 0, 1); 를 루프하여 실현했습니다. 방법은 과학적이지 않지만 효과를 실현할 수 있습니다. 더 과학적인 방법은 buffer 와 배합해야 합니다. 이는 다음 번 노트의 내용으로, 우리는 아직 잠금 해제를 하지 않았습니다
var arrPos = [];
webgl.addEventListener('click', function(e) {
// 좌표 변환
var x = (e.offsetX - webgl.width / 2) / (webgl.width / 2);
var y = (webgl.height / 2 - e.offsetY) / (webgl.height / 2);
console.log(x, y);
// 랜덤 색상
var color = {
r: Math.random(),
g: Math.random(),
b: Math.random(),
a: Math.random()
};
// 좌표, 색상 기록
arrPos.push({
x: x,
y: y,
color: color
});
// canvas 클리어
gl.clear(gl.COLOR_BUFFER_BIT);
// 기록한 모든 좌표 위치에 점 그리기
arrPos.forEach(function(item) {
// 2.attribute 변수에 값 대입
// attribute 변수의 저장 위치를 획득
var a_Position = gl.getAttribLocation(glUtil.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return;
}
// 정점 위치를 attribute 변수에 전달
gl.vertexAttrib3f(a_Position, item.x, item.y, 0.0);
// 색상 설정
// uniform 변수의 저장 위치를 획득
var u_FragColor = gl.getUniformLocation(glUtil.program, 'u_FragColor');
var color = item.color;
// 색상 값을 uniform 변수에 전달
gl.uniform4f(u_FragColor, color.r, color.g, color.b, color.a);
// 점 그리기
gl.drawArrays(gl.POINTS, 0, 1);
});
});
새로운 것은 없고,ただ난폭한 루프일 뿐입니다. 유일하게 주의해야 할 문제는 루프 전의 clear 입니다. 이전 노트에서 이 문제에 언급했습니다: 그리기 완료 후, 색상 버퍼는 리셋되고, 그 중의 내용은 손실됩니다. 효과에서 보면, clear 는 매번 그리기 전에 검은색 배경을 설정하고 있습니다. clear 가 없는 경우, 배경은 투명해집니다 (vec4(0.0, 0.0, 0.0, 0.0))
三.DEMO
위 코드를 포함한 완전한 예는, 다음을 참조:http://www.ayqy.net//temp/webgl/uniform/index.html
四.정리
우리는 점点点点으로 찬란한星空을 점켜내는 효과를 실현했습니다. 퍼포먼스를 고려하지 않는다면, 이렇게 실현하는 것은 나쁘지 않습니다. 왜냐하면 다음 번 노트에서 소개할 buffer 는 더 번거로워 보이지만, 이점도 있기 때문입니다. buffer 가 있으면 1 회에 한 조의 데이터를 전달할 수 있고, 향후 삼각형을 그리고, 삼각형에 색을 칠하고, 텍스처를 붙이는 것이 매우 편리해집니다
loop draw a point 는 결국 长久之計가 아닙니다. 1 개 1 개의 점으로 삼각형을拼을 수는 없습니다. 하물며 3D 모델도 있습니다. buffer 는 매우 필요합니다
참고 자료
- 《WebGL 프로그래밍 가이드》
아직 댓글이 없습니다