我们公司网站提供了一个内置Flash的“随机分片生成器”,可以在网站标题下方随机创建多个重叠的彩色分片图形。
http://www.clarendonmarketing.com
我正在尝试使用HTML5复制此效果,虽然我可以轻松地生成随机分片,但混合重叠(以Adobe术语相乘)证明是一种挑战。
我有一个解决方案,它基本上在绘制每个分片之前创建所有画布的像素数据的数组,然后在绘制每个分片后使用画布的像素数据生成另一个数组。然后比较两者,并在第一个数组中找到非透明像素,其中第二个数组中的对应像素与当前选定的填充颜色匹配,然后使用由“乘法”函数确定的新颜色值重新绘制它(topValue * bottomValue / 255)。
一般情况下,这样可以正常工作并达到预期的效果,除了重叠碎片的边缘,产生锯齿状效果。
我认为这与浏览器的抗锯齿有关。我已经尝试复制计算像素的原始像素的alpha通道值,但这似乎没有帮助。
使用Javascript:
// Random Shard Generator v2 (HTML5)
var theCanvas;
var ctx;
var maxShards = 6;
var minShards = 3;
var fillArray = new Array(
[180,181,171,255],
[162,202,28,255],
[192,15,44,255],
[222,23,112,255],
[63,185,127,255],
[152,103,158,255],
[251,216,45,255],
[249,147,0,255],
[0,151,204,255]
);
var selectedFill;
window.onload = function() {
theCanvas = document.getElementById('shards');
ctx = theCanvas.getContext('2d');
//ctx.translate(-0.5, -0.5)
var totalShards = getRandom(maxShards, minShards);
for(i=0; i<=totalShards; i++) {
//get snapshot of current canvas
imgData = ctx.getImageData(0,0,theCanvas.width,theCanvas.height);
currentPix = imgData.data
//draw a shard
drawRandomShard();
//get snapshot of new canvas
imgData = ctx.getImageData(0,0,theCanvas.width,theCanvas.height);
pix = imgData.data;
//console.log(selectedFill[0]+','+selectedFill[1]+','+selectedFill[2]);
//alert('break')
//CALCULATE THE MULTIPLIED RGB VALUES FOR OVERLAPPING PIXELS
for (var j = 0, n = currentPix.length; j < n; j += 4) {
if (
//the current pixel is not blank (alpha 0)
(currentPix[j+3]>0)
&& //and the new pixel matches the currently selected fill colour
(pix[j]==selectedFill[0] && pix[j+1]==selectedFill[1] && pix[j+2]==selectedFill[2])
) { //multiply the current pixel by the selected fill colour
//console.log('old: '+currentPix[j]+','+currentPix[j+1]+','+currentPix[j+2]+','+currentPix[j+3]+'\n'+'new: '+pix[j]+','+pix[j+1]+','+pix[j+2]+','+pix[j+3]);
pix[j] = multiply(selectedFill[0], currentPix[j]); // red
pix[j+1] = multiply(selectedFill[1], currentPix[j+1]); // green
pix[j+2] = multiply(selectedFill[2], currentPix[j+2]); // blue
}
}
//update the canvas
ctx.putImageData(imgData, 0, 0);
}
};
function drawRandomShard() {
var maxShardWidth = 200;
var minShardWidth = 30;
var maxShardHeight = 16;
var minShardHeight = 10;
var minIndent = 4;
var maxRight = theCanvas.width-maxShardWidth;
//generate a random start point
var randomLeftAnchor = getRandom(maxRight, 0);
//generate a random right anchor point
var randomRightAnchor = getRandom((randomLeftAnchor+maxShardWidth),(randomLeftAnchor+minShardWidth));
//generate a random number between the min and max limits for the lower point
var randomLowerAnchorX = getRandom((randomRightAnchor - minIndent),(randomLeftAnchor + minIndent));
//generate a random height for the shard
var randomLowerAnchorY = getRandom(maxShardHeight, minShardHeight);
//select a fill colour from an array
var fillSelector = getRandom(fillArray.length-1,0);
//console.log(fillSelector);
selectedFill = fillArray[fillSelector];
drawShard(randomLeftAnchor, randomLowerAnchorX, randomLowerAnchorY, randomRightAnchor, selectedFill);
}
function drawShard(leftAnchor, lowerAnchorX, lowerAnchorY, rightAnchor, selectedFill) {
ctx.beginPath();
ctx.moveTo(leftAnchor,0);
ctx.lineTo(lowerAnchorX,lowerAnchorY);
ctx.lineTo(rightAnchor,0);
ctx.closePath();
fillColour = 'rgb('+selectedFill[0]+','+selectedFill[1]+','+selectedFill[2]+')';
ctx.fillStyle=fillColour;
ctx.fill();
};
function getRandom(high, low) {
return Math.floor(Math.random() * (high-low)+1) + low;
}
function multiply(topValue, bottomValue){
return topValue * bottomValue / 255;
};
答案 0 :(得分:5)
你真的需要乘法吗?为什么不使用较低的不透明度混合?
ctx.globalAlpha = 0.6;
for(var i=totalShards;i--;) drawRandomShard();
编辑:如果你真的需要乘法,那么leave it to the professionals,因为带alpha值的乘法模式有点棘手:
<script type="text/javascript" src="context_blender.js"></script>
<script type="text/javascript">
var ctx = document.querySelector('canvas').getContext('2d');
// Create an off-screen canvas to draw shards to first
var off = ctx.canvas.cloneNode(true).getContext('2d');
var w = ctx.canvas.width, h = ctx.canvas.height;
for(var i=totalShards;i--;){
off.clearRect(0,0,w,h); // clear the offscreen context first
drawRandomShard(off); // modify to draw to the offscreen context
off.blendOnto(ctx,'multiply'); // multiply onto the main context
}
</script>