将JavaScript变量发送到片段着色器
我一直在拼凑在线示例来制作Mandelbrot集片段着色器。顶点着色器基本上什么都不做,它指定将JavaScript变量发送到片段着色器,javascript,glsl,webgl,Javascript,Glsl,Webgl,我一直在拼凑在线示例来制作Mandelbrot集片段着色器。顶点着色器基本上什么都不做,它指定gl\u位置,片段着色器执行一些数学运算来计算图像 但是,我有许多#define要用JavaScript控制变量替换,我不知道如何做到这一点。如果可以举一个例子,说明如何在下面的代码中用JavaScript指定的变量替换#定义MAX_迭代200,那么我可能会找出其余的例子。我认为我需要指定一个统一的或变化的,但不确定如何管理从JavaScript到GLSL的通信 另外,我不明白aPosition是如何在
gl\u位置
,片段着色器执行一些数学运算来计算图像
但是,我有许多#define
要用JavaScript控制变量替换,我不知道如何做到这一点。如果可以举一个例子,说明如何在下面的代码中用JavaScript指定的变量替换#定义MAX_迭代200
,那么我可能会找出其余的例子。我认为我需要指定一个统一的
或变化的
,但不确定如何管理从JavaScript到GLSL的通信
另外,我不明白aPosition
是如何在JavaScript和顶点着色器之间工作的,我得到的与示例基本相同
JavaScript,我想只有init()
对SO读者来说是重要的,如果需要,其余的都会发布:
var canvas, gl, shaderProgram;
function draw() {
window.requestAnimationFrame(draw, canvas);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function init() {
canvas = document.getElementById("theCanvas");
gl = initGl(canvas);
if (!gl) {
alert("Could not initialize WebGL");
return;
}
shaderProgram = initShaders();
if (!shaderProgram) {
alert("Could not initialize shaders");
return;
}
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
1.0, 1.0,
]),
gl.STATIC_DRAW
);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
var aPosition = gl.getAttribLocation(shaderProgram, "aPosition");
gl.enableVertexAttribArray(aPosition);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
draw();
}
function initGl(inCanvas) {
gl = false;
try { gl = inCanvas.getContext("webgl") || inCanvas.getContext("experimental-webgl"); }
catch (e) {}
return !gl ? false : gl;
}
function initShaders() {
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, document.getElementById("vertexShader").text);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(vertexShader));
return false;
}
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, document.getElementById("fragmentShader").text);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(fragmentShader));
return false;
}
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) return false;
gl.useProgram(shaderProgram);
return shaderProgram;
}
顶点着色器:
attribute vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
}
片段着色器,最大迭代次数
,XMIN
,YMIN
,WH
应在JavaScript中控制:
#ifdef GL_FRAGEMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
precision mediump int;
#define MAX_ITERATIONS 200
#define XMIN -2.5
#define YMIN -2.0
#define WH 4.0
#define LOG_TWO log(2.0)
#define LOG_MAX log(200.0)
void main() {
// Normalized pixel position to complex plane position
float maxPwh = max(640.0, 480.0);
float x = XMIN+(gl_FragCoord.x/maxPwh)*WH;
float y = YMIN+(gl_FragCoord.y/maxPwh)*WH;
// Complex plane window offsets for pixel windows that are not square
float halfDelta = WH/maxPwh*0.5;
x -= min((640.0-480.0)*halfDelta, 0.0);
y -= min((480.0-640.0)*halfDelta, 0.0);
// Mandelbrot Set code
float zr = x;
float zi = y;
int iterations = 0;
for (int i = 0; i < MAX_ITERATIONS; i++) {
iterations = i;
float sqZr = zr*zr;
float sqZi = zi*zi;
float twoZri = 2.0*zr*zi;
zr = sqZr-sqZi+x;
zi = twoZri+y;
if (sqZr+sqZi > 16.0) break;
}
if (iterations == MAX_ITERATIONS-1) gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
else {
float fn = float(iterations)+1.0-log(log(sqrt(zr*zr+zi*zi)))/LOG_TWO;
float logVal = log(fn)/LOG_MAX;
gl_FragColor = vec4(logVal, logVal, logVal, 1.0);
}
}
\ifdef GL\u FRAGEMENT\u精度高
高精度浮点;
#否则
精密中泵浮子;
#恩迪夫
精密中泵;
#定义最大迭代次数200次
#定义XMIN-2.5
#定义YMIN-2.0
#定义WH4.0
#定义两个日志(2.0)
#定义LOG_MAX LOG(200.0)
void main(){
//将像素位置归一化为复平面位置
浮动最大值=最大值(640.0480.0);
浮点x=XMIN+(gl_FragCoord.x/maxPwh)*;
浮动y=YMIN+(gl_FragCoord.y/maxPwh)*WH;
//非正方形像素窗口的复杂平面窗口偏移
浮动半三角形=WH/maxPwh*0.5;
x-=最小值((640.0-480.0)*半三角形,0.0);
y-=最小值((480.0-640.0)*半三角形,0.0);
//Mandelbrot集码
浮动zr=x;
浮点数zi=y;
int迭代次数=0;
对于(int i=0;i16.0)断裂;
}
如果(迭代次数==最大迭代次数-1)gl\u FragColor=vec4(1.0,1.0,1.0,1.0);
否则{
float fn=float(迭代)+1.0-log(log(sqrt(zr*zr+zi*zi)))/logtwo;
float logVal=log(fn)/log_MAX;
gl_FragColor=vec4(logVal,logVal,logVal,1.0);
}
}
简而言之,您基本上有两种选择
uniform float foo;
在JavaScript中,编译并链接该着色器,然后查找制服的位置
var locationOfFoo = gl.getUniformLocation(someProgram, "foo");
现在,您可以使用将值传递给GLSL
gl.useProgram(someProgram)
gl.uniform1f(locationOfFoo, valueToPass);
#define MAX_INTERATIONS %maxIterations%
#define XMIN %xMin%
(1) 上面是用来传递经常变化的东西的#2用于在编译着色器之前更改着色器#1是几乎100%的WebGL程序中使用的一种技术#2在动态生成着色器时经常使用,许多游戏引擎都是这样做的。我花了大约45分钟来实现gman的回答,因为 我一直犯愚蠢的小错误。下面是一个完整的工作代码 创建可调整平铺贴图的示例 测试地点:Chrome、Internet Explorer和Edge:
GL_瓷砖_试验台
p{font size:12pt;}
h3,p,输入,按钮,br{
填充:0px;
边际:0px;
字体系列:“安达勒单声道”;
}
按钮,输入{
填充:10px;
}
高精度浮点;
属性向量2 a_位置;
void main(){
gl_位置=vec4(a_位置,0,1);
}
//必须在声明前声明精度
//任何制服:
////////////////////////////////////////////////
#ifdef GL_碎片_精度_高
高精度浮点;
#否则
精密中泵浮子;
#恩迪夫
精密中泵;
////////////////////////////////////////////////
#定义画布WID640.0
#定义CANVAS_HIG 480.0
#定义TIL_WID 64.0
#定义直到64.0
//暴露于HTML/JAVASCRIPT的制服:
均匀浮动直到编辑;
均匀浮动直到高编辑;
浮动至宽;
浮到高处;
void main(){
//如果用户未设置制服,
//使用#定义设置的默认值
//==========================================//
如果(直到宽度编辑>0.0){
til_wid=til_wid_编辑;
}否则{
til_wid=til_wid;
}
如果(直到高编辑>0.0){
til_hig=til_hig_EDIT;
}否则{
til_hig=til_hig;
}
//==========================================//
//注:在“gl_FragCoord”范围内:
//******************************************//
//web gl:在像素/画布坐标方面。
//OpenGL:从0到1。
//******************************************//
//:计算屏幕上显示的瓷砖数量:
//:这可能是分数:
float NUM_TIL_X=画布宽度/TIL宽度;
float NUM_TIL_Y=画布高度/高度;
vec2-FC_-MOD;
FC_MOD.x=gl_FragCoord.x;
FC_MOD.y=gl_FragCoord.y;
//您希望所有磁贴都具有完整的范围
//颜色,所以你总是通过
//画布宽和画布高,按
//#每个轴上的瓷砖数量,表示
//随着瓷砖厚度的增加,坡度变得更陡
//增加。
FC_MOD.x=MOD(
var maxIterations = 123;
var xMin = 4.5;
shaderSource = shaderSource.replace(/%maxIterations%/g, maxIterations);
shaderSource = shaderSource.replace(/%xMin%/g, xMin);