【问题标题】:Unable to reproduce properly the copy of image from one canvas to other canvas无法将图像从一个画布正确复制到另一个画布
【发布时间】:2016-09-26 21:32:49
【问题描述】:

我的主要座右铭是将画布上显示的图像(服务器)传输到客户端,以便它在自己的画布元素中显示相同的图像。

但现在,我所做的是,在服务器端本身,我在同一个网页中创建另一个 canavs,

我的代码是:

var canvas = document.getElementById("canvas_win");
var gl;
var canvas1 = document.getElementById("canvas_win1");
var gl1;

try {
    gl = canvas.getContext("webgl", {premultipliedAlpha: false}) || canvas.getContext("experimental-webgl",{premultipliedAlpha: false});
} catch (e) {
}
if (!gl) {
    alert("Could not initialise WebGL, sorry :-(");
}   

try {
    gl1 = canvas.getContext("webgl", {premultipliedAlpha: false}) || canvas.getContext("experimental-webgl",{premultipliedAlpha: false});
} catch (e) {
}
if (!gl) {
    alert("Could not initialise WebGL, sorry :-(");
}



var dataURLstring = canvas_win.toDataURL();
var ctx = canvas1.getContext('2d');  
ctx.clearRect(0, 0, canvas_win1.width, canvas_win1.height);
var img = new Image;
img.onload = function(){
ctx.drawImage(img,0,0); // Or at whatever offset you like
};
img.src = dataURLstring;

所以我正在运行基于 WebGL 的体积渲染,因此对于 canvas_win 上的任何 gui 操作都会生成一个渲染图像并显示在它自己的画布上。现在,这个显示的图像我需要复制到另一个画布。 我正在尝试将先前复制的图像清除到 canvas_win1 并显示从 canvas_win 复制的当前图像。

但我在复制的图像中看到了一些额外的阴影。我不知道是什么原因造成的。在这里,我附上了画布的快照。左边是原版。 Rigt 是复制的版本。

另一个观察,有时显示的图像很完美,但有时会添加黑色阴影。我正在 Google Chrome 版本 52.0.2743.82 m(64 位)上对其进行测试,并在 Mozilla Firefox 47.0.1 上进行了测试

对此的任何见解都是有用的。

问候, 普拉杰瓦尔

/* 
	Copyright 2011 Vicomtech

	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
*/

// Volumerc.js

/*
GLobal variables
*/

/*
Zoom factor
*/
var zoom=2.0;

/*
*/
var drawVolume;

var time, end, start;
var count=0;
/*
Mouse Positions
*/
var mouseDown = false;
var lastMouseX = null;
var lastMouseY = null;
var mouseZoom = null;


/*
Matrix which rotates the cube
*/
var objectRotationMatrix = createRotationMatrix(90, [1, 0, 0]).x(createRotationMatrix(180, [0, 0, 1]));


/*
load_resource

get a document from a web direction
*/
function load_resource(url) {
	var req = new XMLHttpRequest();
	req.open('GET', url, false);
	req.overrideMimeType('text/plain; charset=x-user-defined');
	req.send(null);

	if (req.status != 200) return '';
	return req.responseText;
}


/*
initShaders

function to get the shaders from an url and compile them
*/
function initShaders(gl, vertex_url, fragment_url)
{
	var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
	var vertexShader = gl.createShader(gl.VERTEX_SHADER);

	var src = load_resource(vertex_url);
	gl.shaderSource(vertexShader, src);
	gl.compileShader(vertexShader);

	if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS))
	{
		return null;
	}

	src = load_resource(fragment_url);

	gl.shaderSource(fragmentShader, src);
	gl.compileShader(fragmentShader);

	if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS))
	{
		return null;
	}

	var shaderProgram = gl.createProgram();

	gl.attachShader(shaderProgram, vertexShader);
	gl.attachShader(shaderProgram, fragmentShader);
	gl.linkProgram(shaderProgram);

	if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
		alert("Linking " + vertex_url + "+"+ fragment_url + "\n ------------ \n" + gl.getProgramInfoLog(shaderProgram));
	}

	gl.useProgram(shaderProgram);

	shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
	gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

	shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
	gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);

	shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
	shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");

	return shaderProgram
}


/*
cubeBuffer

Create a cube in webgl with color vertex for each axis
*/
function cubeBuffer(gl)
{
	var cube = new Object();
	cube.VertexPositionBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, cube.VertexPositionBuffer);
	var vertices = [
		// Front face
		0.0, 0.0, 1.0,
		1.0, 0.0, 1.0,
		1.0, 1.0, 1.0,
		0.0, 1.0, 1.0,

		// Back face
		0.0, 0.0, 0.0,
		0.0, 1.0, 0.0,
		1.0, 1.0, 0.0,
		1.0, 0.0, 0.0,

		// Top face
		0.0,  1.0, 0.0,
		0.0,  1.0, 1.0,
		1.0,  1.0, 1.0,
		1.0,  1.0, 0.0,

		// Bottom face
		0.0, 0.0, 0.0,
		1.0, 0.0, 0.0,
		1.0, 0.0, 1.0,
		0.0, 0.0, 1.0,

		// Right face
		1.0, 0.0, 0.0,
		1.0, 1.0, 0.0,
		1.0, 1.0, 1.0,
		1.0, 0.0, 1.0,

		// Left face
		0.0, 0.0, 0.0,
		0.0, 0.0, 1.0,
		0.0, 1.0, 1.0,
		0.0, 1.0, 0.0,
	];
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
	cube.VertexPositionBuffer.itemSize = 3;
	cube.VertexPositionBuffer.numItems = 24;

	cube.VertexColorBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, cube.VertexColorBuffer);

	var colors = [
		// Front face
		0.0, 0.0, 1.0, 1.0,
		1.0, 0.0, 1.0, 1.0,
		1.0, 1.0, 1.0, 1.0,
		0.0, 1.0, 1.0, 1.0,

		// Back face
		0.0, 0.0, 0.0, 1.0,
		0.0, 1.0, 0.0, 1.0,
		1.0, 1.0, 0.0, 1.0,
		1.0, 0.0, 0.0, 1.0,

		// Top face
		0.0, 1.0, 0.0, 1.0,
		0.0, 1.0, 1.0, 1.0,
		1.0, 1.0, 1.0, 1.0,
		1.0, 1.0, 0.0, 1.0,

		// Bottom face
		0.0, 0.0, 0.0, 1.0,
		1.0, 0.0, 0.0, 1.0,
		1.0, 0.0, 1.0, 1.0,
		0.0, 0.0, 1.0, 1.0,

		// Right face
		1.0, 0.0, 0.0, 1.0,
		1.0, 1.0, 0.0, 1.0,
		1.0, 1.0, 1.0, 1.0,
		1.0, 0.0, 1.0, 1.0,

		// Left face
		0.0, 0.0, 0.0, 1.0,
		0.0, 0.0, 1.0, 1.0,
		0.0, 1.0, 1.0, 1.0,
		0.0, 1.0, 0.0, 1.0
	];

	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
	cube.VertexColorBuffer.itemSize = 4;
	cube.VertexColorBuffer.numItems = 24;

	cube.VertexIndexBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cube.VertexIndexBuffer);
	var VertexIndices = [
	0, 1, 2,      0, 2, 3,    // Front face
	4, 5, 6,      4, 6, 7,    // Back face
	8, 9, 10,     8, 10, 11,  // Top face
	12, 13, 14,   12, 14, 15, // Bottom face
	16, 17, 18,   16, 18, 19, // Right face
	20, 21, 22,   20, 22, 23  // Left face
	]
	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(VertexIndices), gl.STATIC_DRAW);
	cube.VertexIndexBuffer.itemSize = 1;
	cube.VertexIndexBuffer.numItems = 36;

	return cube;
}

/*
setMatrixUniforms
	
define the model matrix and projection matrix for the model
*/
function setMatrixUniforms(gl)
{
	gl.uniformMatrix4fv(gl.shaderProgram.pMatrixUniform, false, new Float32Array(pMatrix.flatten()));
	gl.uniformMatrix4fv(gl.shaderProgram.mvMatrixUniform, false, new Float32Array(mvMatrix.flatten()));
}

/*
drawCube

render the cube
*/
function drawCube(gl,cube)
{
	gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

	perspective(45.0, 1.0, 0.1, 100.0);
	loadIdentity();

	mvTranslate([0.0, 0.0, -zoom])
	mvPushMatrix();
	multMatrix(objectRotationMatrix);
	mvTranslate([-0.5, -0.5, -0.5])
	gl.bindBuffer(gl.ARRAY_BUFFER, cube.VertexPositionBuffer);
	gl.vertexAttribPointer(gl.shaderProgram.vertexPositionAttribute, cube.VertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

	gl.bindBuffer(gl.ARRAY_BUFFER, cube.VertexColorBuffer);
	gl.vertexAttribPointer(gl.shaderProgram.vertexColorAttribute, cube.VertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cube.VertexIndexBuffer);
	setMatrixUniforms(gl);
	gl.drawElements(gl.TRIANGLES, cube.VertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

	mvPopMatrix();
}

/*
initFBO

initializes the Frame Buffer Objects
*/
function initFBO(gl, width, height)
{
	var fbo = gl.createFramebuffer();
	gl.bindFramebuffer(gl.FRAMEBUFFER,fbo);

	fbo.depthbuffer = gl.createRenderbuffer();
	gl.bindRenderbuffer(gl.RENDERBUFFER,fbo.depthbuffer);

	gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);

	gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fbo.depthbuffer);

	fbo.tex = gl.createTexture();
	gl.bindTexture(gl.TEXTURE_2D, fbo.tex);
	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(width*height*4));

	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

	gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbo.tex, 0);

	switch(gl.checkFramebufferStatus(gl.FRAMEBUFFER))
	{
		case gl.FRAMEBUFFER_COMPLETE:
			//alert("Framebuffer OK");
		break;
		case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
			alert("Framebuffer incomplete attachment");
		break;
		case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
			alert("Framebuffer incomplete missing attachment");
		break;
		case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
			alert("Framebuffer incomplete dimensions");
		break;
		case gl.FRAMEBUFFER_UNSUPPORTED:
			alert("Framebuffer unsuported");
		break;
	}
	return fbo
}

/*
handleLoadedTexture

Create a texture from an image
*/
function handleLoadedTexture(gl,image, texture)
{
	gl.bindTexture(gl.TEXTURE_2D, texture);
	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
	gl.bindTexture(gl.TEXTURE_2D, null);
}

/*
initTexture

read the textures from internet and set the callbacks for the texture creation
*/
function initTexture(gl, imgData, imgTF)
{
	gl.tf_tex = gl.createTexture();
	gl.tf_img = new Image();
	gl.tf_img.onload = function()
	{
		handleLoadedTexture(gl, gl.tf_img, gl.tf_tex);
	}
	gl.tf_img.src = imgTF;


	gl.vol_tex = gl.createTexture();
	gl.vol_img = new Image();
	gl.vol_img.onload = function()
	{
		handleLoadedTexture(gl,gl.vol_img,gl.vol_tex)
		setTimeout(drawVolume, 1);
	}
	gl.vol_img.src = imgData;
	//gl.vol_img.src = "./skull.png";
	//gl.vol_img.src = "./engine.png";
}

/*
main function
*/
function volumerc_main(rayfrag, imgData, imgTF)
{
	start = new Date().getTime();
	document.getElementById("demo").innerHTML = start; 
	
	var canvas = document.getElementById("canvas_win");
	var gl;
	var canvas1 = document.getElementById("canvas_win1");
	
	
	try {
		//gl = canvas.getContext("webgl", {alpha: false}) || canvas.getContext("experimental-webgl",{alpha: false});
		gl = canvas.getContext("webgl", {premultipliedAlpha: false}) || canvas.getContext("experimental-webgl",{premultipliedAlpha: false});
	} catch (e) {
	}
	if (!gl) {
		alert("Could not initialise WebGL, sorry :-(");
	}	
	

	gl.shaderProgram_BackCoord = initShaders(gl,'./simple.vert','./simple.frag');
	gl.shaderProgram_RayCast = initShaders(gl,'./raycast.vert',rayfrag, imgData, imgTF);
	
	gl.fboBackCoord = initFBO(gl, canvas.width, canvas.height);
	initTexture(gl, imgData, imgTF);

	var cube = cubeBuffer(gl);

	canvas.onmousedown = handleMouseDown;
	document.onmouseup = handleMouseUp;
	document.onmousemove = handleMouseMove;

	
	

	drawVolume = function()
	{
		
		ctx.clearRect(0, 0, canvas_win1.width, canvas_win1.height);	
		
		
		gl.clearColor(0.0, 0.0, 0.0, 0.0);
		gl.enable(gl.DEPTH_TEST);

		gl.bindFramebuffer(gl.FRAMEBUFFER, gl.fboBackCoord);
		gl.shaderProgram = gl.shaderProgram_BackCoord;
		gl.useProgram(gl.shaderProgram);
		gl.clearDepth(-50.0);
		gl.depthFunc(gl.GEQUAL);
		drawCube(gl,cube);

		gl.bindFramebuffer(gl.FRAMEBUFFER, null);
		gl.shaderProgram = gl.shaderProgram_RayCast;
		gl.useProgram(gl.shaderProgram);
		gl.clearDepth(50.0);
		gl.depthFunc(gl.LEQUAL);

		gl.activeTexture(gl.TEXTURE0);
		gl.bindTexture(gl.TEXTURE_2D, gl.fboBackCoord.tex);

		gl.activeTexture(gl.TEXTURE1);
		gl.bindTexture(gl.TEXTURE_2D, gl.vol_tex);

		gl.activeTexture(gl.TEXTURE2);
		gl.bindTexture(gl.TEXTURE_2D, gl.tf_tex);

		gl.uniform1i(gl.getUniformLocation(gl.shaderProgram, "uBackCoord"), 0);
		gl.uniform1i(gl.getUniformLocation(gl.shaderProgram, "uVolData"), 1);
		gl.uniform1i(gl.getUniformLocation(gl.shaderProgram, "uTransferFunction"), 2);

		//Set Texture
		drawCube(gl,cube);
		//console.log(gl.getImageData(0, 0, 500, 500)); 
		//document.getElementById("demo").innerHTML = gl.getImageData(0, 0, 500, 500);
		//var img1 = new Image();
         
		 
		 
		 var dataURLstring = canvas.toDataURL();
			
		 var img = new Image;
		 img.src = dataURLstring;
		 img.onload = function(){
         ctx.drawImage(img,0,0); // Or at whatever offset you like
		 };
		 
		 
		 
		//img1.src = canvas.toDataURL();
		//document.getElementById("demo").innerHTML = gl;
		end = new Date().getTime();
		document.getElementById("dem").innerHTML = end-start;	
	}

	
	
	setTimeout(drawVolume, 15);
	
	
	
}

/*
MouseDown callback
*/
function handleMouseDown(event) {
	if (event.altKey){
		mouseZoom = true;
	}else {
		mouseDown = true;
		lastMouseX = event.clientX;
		lastMouseY = event.clientY;
	}
}
/*
MouseUp callback
*/
function handleMouseUp(event)
{
	mouseDown = false;
	mouseZoom = false;
}

/*
MouseMove callback
*/
function handleMouseMove(event)
{
	//count=count+1;
	//document.getElementById("dem").innerHTML = count;
	
//alert('Execution time: ' + time);
	if (mouseDown) {
		var newX = event.clientX;
		var newY = event.clientY;

		var deltaX = newX - lastMouseX
		var newRotationMatrix = createRotationMatrix(deltaX / 10, [0, 1, 0]);

		var deltaY = newY - lastMouseY;
		newRotationMatrix = newRotationMatrix.x(createRotationMatrix(deltaY / 10, [1, 0, 0]));

		objectRotationMatrix = newRotationMatrix.x(objectRotationMatrix);

		lastMouseX = newX
		lastMouseY = newY;
		setTimeout(drawVolume, 1);

	} else if (mouseZoom) {
		var newX = event.clientX;
		var newY = event.clientY;

		var deltaX = newX - lastMouseX;
		var deltaY = newY - lastMouseY;

		zoom -= (deltaX+deltaY)/100,0;

		lastMouseX = newX;
		lastMouseY = newY;
		setTimeout(drawVolume, 1);

	}
	return;
}
<HTML><HEAD><META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<TITLE>Real-Time Interactive Visualization of Volumetric Data with WebGL</TITLE>
<SCRIPT type="text/javascript" src="sylvester.js"></SCRIPT>
<SCRIPT type="text/javascript" src="glUtils.js"></SCRIPT>
<SCRIPT type="text/javascript" src="glAux.js"></SCRIPT>
<SCRIPT type="text/javascript" src="volumerc.js"></SCRIPT>

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-40928041-1', 'volumerc.org');
  ga('send', 'pageview');

</script>

<!-- 
</HEAD><BODY onload="volumerc_main('./raycast-color.frag','./aorta-low.jpg','./tfold.png');" bgcolor="white"> -->
<button type="button" onclick="volumerc_main('./raycast-color.frag','./aorta-high512.jpg','./tfold.png');">Load</button>
<CENTER>
<H1>Real-Time Interactive Visualization of Volumetric Data with WebGL</H1>

<canvas id="canvas_win" width="512" height="512" style="border:1px solid black"></canvas>

<canvas id="canvas_win1" width="512" height="512" style="border:1px solid black"></canvas>

</CENTER>
</BODY>
</HTML>

【问题讨论】:

  • 用于创建 WebGL 上下文的代码在哪里?

标签: javascript canvas webgl


【解决方案1】:

Canvas2D 画布总是使用 预乘 alpha,通常无法在 canvas2d API 中获取无效颜色。

另一方面,WebGL 很容易制作无效颜色,因为 您需要确保写入画布的值预乘 alpha(或将画布设置为 premultipliedAlpha:假)

这是一个例子。运行。

var gl = document.querySelector("#webgl").getContext("webgl");

gl.clearColor(1, 0.8, 0.3, 0.5);  // <=- INVALID COLOR
gl.clear(gl.COLOR_BUFFER_BIT);

var img = new Image();
img.src = gl.canvas.toDataURL();
document.body.appendChild(img);
img, canvas { 
  border: 1px solid black; 
  margin 5px; 
  width: 150px;
  background: #888;
}
&lt;canvas id="webgl"&gt;&lt;/canvas&gt;

请注意图像与画布不匹配。为什么?

1, 0.8, 0.3, 0.5

被写入画布,这是一种无效颜色,因为它没有被 alpha 预乘。

RGB *= A

如果是,那么最大值 (RED = 1.0) 现在是 0.5

R * A = 1.0 * 0.5 = 0.5

所以当您调用toDataURL 时会发生什么情况是您的值未预乘 alpha(因为 png 中的值是未预乘的 alpha。要取消预乘,我们除以 alpha 所以

1, 0.8, 0.3, 0.5

变成

1 / 0.5, 0.8 / 0.5, 0.3 / 0.5, 0.5

=

2, 1.6, 0.6, 0.5

现在将其限制为 1

1, 1, 0.6, 0.5

这是放入 PNG 的颜色值。

.PNG 文件然后被加载到浏览器中。然后浏览器预乘这些值(这就是它能够正确显示透明 .PNG 颜色的方式)

所以

RGB *= A

1 * 0.5, 1 * 0.5, 0.6 * 0.5

0.5, 0.5, 0.3, 0.5   <=- The color displayed for the image

如果您希望它们匹配,您有多种选择

  • 确保将预乘 alpha 写入画布

  • 关闭预乘 alpha

    someCanvas.getContext("webgl", {premutlipliedAlpha: false});
    
  • 关闭阿尔法

    someCanvas.getContext("webgl", {alpha: false});
    

至于提供图像,为什么不将其作为 .PNG 或 .JPG 而不是 dataURL 提供呢?那时它会更小更压缩。

    // Assuming node.js
    var base64PartOfDataURL = dataUrl.split(",")[0]
    var buf = new Buffer(base64PartOfDataURL, 'base64'); 

    // now serve buf as your result
    res.set('Content-Type', 'image/png');
    res.write(buf);
    res.end();

或者类似的东西。

【讨论】:

  • 在预乘 alpha 混合模式下,例如 (1.0,1.0,1.0,0.0) 会变成加法混合。事实上,alpha 值有点像在正常混合和加法混合之间徘徊:amindforeverprogramming.blogspot.ca/2013/07/….
  • 它在画布中看起来就像是相加的,但是如果你调用 toDataURL 然后尝试显示生成的 png 你会从 1,1 得到 0,0,0,0 ,1,0
  • @gman 抱歉回复晚了。好吧,我确实按照您的建议将预乘 alpha 设置为 false 进行了更改。然而结果并没有改善。关于我哪里出错的任何提示。我已经更新了主要描述中的代码。
  • 您还没有明确说明您是如何创建这 2 个图像的。第二张图片只是一个图片标签还是在 WebGL 中绘制的?如果它是在 WebGL 中绘制的,您需要显示您的绘图代码。否则我不知道。也许你打错了什么?尝试使用 gl.colorMask(false, false, false, true); gl.clearColor(1, 1, 1, 1); gl.clear(gl.COLOR_BUFFER_BIT); 将所有 alpha 设置为 1,只是 调用 canvas_win.toDataURL();
  • @gman 在此我附上了 html 页面和 volumerc.js 脚本(在原始帖子中)。在 volumerc.js 脚本中,函数 volumerc_main() 定义了第一个和第二个画布元素,第一个图像是 webgl 元素,而第二个图像元素只是画布元素。在绘制体积函数中,我将 dataurl 复制到 img.src 以显示第二个画布。请看代码。
【解决方案2】:

另一种替代方法是使用 gl.readPixels()。该函数读取渲染数据的缓冲区。这样就可以读取并复制到画布上。正如观察到的那样,数据不匹配不会发生。下面是代码:

var pixels = new Uint8Array(canvas.width * canvas.height * 4);
gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

var imageData = canvas.createImageData(canvas.width, canvas.height);
for (var i = pixels.length - 1; i >= 0; i--) {
imageData.data[i] = pixels[i];
};

canvas.putImageData(imageData, 0, 0);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 2016-03-03
    • 2018-12-25
    • 1970-01-01
    相关资源
    最近更新 更多