Three.js show sRGB colors wrong - three.js

I have problem with PNG sRGB rednering in Three.js. I have this piece of code where I am generation texture from SVG file:
(...) // managing whole SVG data which is long and not important as I will show below
window.temCanvas = document.createElement('canvas');
temCanvas.width = '2048';
temCanvas.height = '454';
window.temContext = temCanvas.getContext('2d', {colorSpace: "srgb", preserveDrawingBuffer: true});
temContext.clearRect(0, 0, 2048, 454);
temContext.drawImage(newTextureTopSVG, 0,0, 2048, 454);
var newTex1 = temCanvas.toDataURL("image/png"); // here should be info about sRGB?
Texture generated this way is showing different colors. All 0 and 255 values are showing correctly but when it is between i.e. rgb(0,128,255) should look like this:
but it is rendered as:
I saved png generated from SVG and compared it to similar png generated from graphic software, there is difference which I see in Notepad++, correct file contain this:
file which is rendering badly (after saving from canvas in Firefox) doesn't contain srgb text:
I suppose I have to add sRGB info here:
var newTex1 = temCanvas.toDataURL("image/png");
How to do it? But shouldn't it be always sRGB for PNG?
Maybe I am wrong and it is possible to force Three.js to show colors correctly by changing something in Material, Texture etc.?
I am using:
renderer.outputEncoding = sRGBEncoding;
I don't want to provide all data, I will edit this post if needed. It is way too long. Especially managing SVG data.

When using renderer.outputEncoding = sRGBEncoding;, sRGB encoded color textures must be configured like so:
texture.encoding = sRGBEncoding;
Otherwise the sRGB workflow is incomplete resulting in wrong colors.

Related

Is there a way to modify alpha in a texture without affecting the RGB values?

I need to sample the RGBA values of a texture, and I'm using the alpha channel to store custom data, not really to as opacity. The problem is that as alpha approaches 0, my RGB values also get multiplied towards 0, but I need them to remain independent.
My first render pass gets rendered into a WebGLRenderTarget, and this is how I'm storing data in GLSL into the alpha channel:
gl_FragColor.rgb = mainColor;
gl_FragColor.a = depthData;
the result shows Alpha fading to white as expected:
My second render pass gets rendered to the canvas, so I read the RGB values from from the first texture in GLSL, with alpha as 1:
gl_FragColor.rgb = texture2D(tColor, vUv).rgb;
gl_FragColor.a = 1.0;
The result should be the regular RGB values of the spheres, but it seems that the RGB values fade to black when Alpha approaches 0.
Is there a way to use the alpha channel as data storage without affecting the RGB values? I've tried setting the target texture's premultiplyAlpha = false as follows, but it doesn't change anything:
var target = new THREE.WebGLRenderTarget(
window.innerWidth,
window.innerHeight, {
format: THREE.RGBAFormat,
type: THREE.UnsignedByteType
});
target.texture.premultiplyAlpha = false;
Update:
I was building a working demo here, and I was unable to reproduce the bug. It looks like I'm going to have to rip apart my entire project until I get to the bottom of this...

Do I need all these statements to get the data array of an image in HTML5 canvas?

I am loading a pixel font file as a png image. I then use it to draw each character to canvas by writing to the buffer imageData.data clamped array and then using putImageData.
Is there a simpler way to get the data array from the png image apart from loading the image as fontImage and then these 7 lines ...
let fontCanvas = document.createElement("canvas");
fontCanvas.width = fontImage.width;
fontCanvas.height = fontImage.height;
let fontContext = fontCanvas.getContext("2d");
fontContext.drawImage(fontImage, 0, 0);
let fontBank = fontContext.getImageData(0,0,fontCanvas.width,fontCanvas.height);
let fontData = fontBank.data;
Thanks.

Writing a greyscale video using Videowriter/avifile

I am writing a function that generates a movie mimicking a particle in a fluid. The movie is coloured and I would like to generate a grayscaled movie for the start. Right now I am using avifile instead of videowriter. Any help on changing this code to get grayscale movie? Thanks in advance.
close all;
clear variables;
colormap('gray');
vidObj=avifile('movie.avi');
for i=1:N
[nx,ny]=coordinates(Lx,Ly,Nx,Ny,[x(i),-y(i)]);
[xf,yf]=ndgrid(nx,ny);
zf=zeros(size(xf))+z(i);
% generate a frame here
[E,H]=nfmie(an,bn,xf,yf,zf,rad,ns,nm,lambda,tf_flag,cc_flag);
Ecc=sqrt(real(E(:,:,1)).^2+real(E(:,:,2)).^2+real(E(:,:,3)).^2+imag(E(:,:,1)).^2+imag(E(:,:,2)).^2+imag(E(:,:,3)).^2);
clf
imagesc(nx/rad,ny/rad,Ecc);
writetif(Ecc,i);
if i==1
cl=caxis;
else
caxis(cl)
end
axis image;
axis off;
frame=getframe(gca);
cdata_size = size(frame.cdata);
data = uint8(zeros(ceil(cdata_size(1)/4)*4,ceil(cdata_size(2)/4)*4,3));
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = [frame.cdata];
frame.cdata = data;
vidObj = addframe(vidObj,frame);
end
vidObj = close(vidObj);
For your frame data, use rgb2gray to convert a colour frame into its grayscale counterpart. As such, change this line:
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = [frame.cdata];
To these two lines:
frameGray = rgb2gray(frame.cdata);
data(1:cdata_size(1),1:cdata_size(2),1:cdata_size(3)) = ...
cat(3,frameGray,frameGray,frameGray);
The first line of the new code will convert your colour frame into a single channel grayscale image. In colour, grayscale images have all of the same values for all of the channels, which is why for the second line, cat(3,frameGray,frameGray,frameGray); is being called. This stacks three copies of the grayscale image on top of each other as a 3D matrix and you can then write this frame to your file.
You need to do this stacking because when writing a frame to file using VideoWriter, the frame must be colour (a.k.a. a 3D matrix). As such, the only workaround you have if you want to write a grayscale frame to the file is to replicate the grayscale image into each of the red, green and blue channels to create its colour equivalent.
BTW, cdata_size(3) will always be 3, as getframe's cdata structure always returns a 3D matrix.
Good luck!

Dynamic text or texture on curved object

I'm a newcomer to three.js and am looking for what approaches are possible to achieve an effect like this:
For a cola can like object as in the image below (minus condensation), I want to change independent bits of text on the surface of the can based on user interaction. The variants of text are fairly arbitrary, too many for pre-baked full can textures. For instance I might want to:
change "Euro 2012" to arbitrary text
change the nutritional stats on the back of the can
show or hide one of the individual music notes
I'm sure it's possible, just looking for what concepts I need to employ. Is it difficult to have multiple textures on the same object? Or to generate arbitrary text and position it on an object and wrap it to the shape of the object?
Any pointers helpful!
You can use image created in a separate canvas as a Three.js texture. Instead of trying to mix and blend multiple textures in Three.js (possible, but tricky and limited control), I think the best solution would be to create the dynamic texture in 2D, totally out of Three.js then just apply the full texture to the can.
You can create your canvas image manually or using canvas image manipulation library of your choice (some possibilities: https://docs.google.com/spreadsheet/ccc?key=0Aqj_mVmuz3Y8dHNhUVFDYlRaaXlyX0xYSTVnalV5ZlE#gid=0 ). Or you can have your template as SVG and modify that (should be quite simple), render that to canvas, then use it as texture.
Using canvas as a texture is very simple:
var canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
var context = canvas.getContext('2d');
// drawing something here....
context.font = "Bold 20px Helvetica";
context.lineWidth = 4;
context.strokeStyle = 'rgba(255,255,255,.8)';
context.fillStyle = "rgba(0,0,0,1)";
context.strokeText("Testing", 4, 22);
context.fillText("Testing", 4, 22);
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;

Actionscript: resizing bitmapdata with smoothing

var bd:BitmapData=new BitmapData(file.width,file.height);
bd.setPixels(new Rectangle(0,0,file.width,file.height),file.raw);
var scale_x_percents:Number = (w / bd.width);
var scale_y_percents:Number = (h / bd.height);
if(!stretch) {
if(bd.width*scale_y_percents>=w) {
scale_x_percents=scale_y_percents;
}
else if(bd.height*scale_x_percents>=h) {
scale_y_percents=scale_x_percents;
}
}
var matrix:Matrix = new Matrix();
matrix.scale(scale_x_percents,scale_y_percents);
var resizedBd:BitmapData = new BitmapData(Math.floor(bd.width*scale_x_percents), Math.floor(bd.height*scale_y_percents), true, 0x000000);
resizedBd.draw(bd, matrix, null, null, null, true); // true is smoothing option, it will blur sharpened pixels
Having problem with images resizing. Looks like smoothing is not working or something is missing in the code. Maybe Matrix should have something more?
Original image:
http://imageshack.us/a/img28/4784/dc7f2ec4b0f3323cdc4e01e.jpg
and it's result:
http://imageshack.us/a/img855/4784/dc7f2ec4b0f3323cdc4e01e.jpg
I can link a bunch of others images. Some strange pixel disposition exist.
Can it be fixed somehow?
I have tested jpeg quality 100% and stage.quality='best', but none of them give the required quality outcome.
It seems that your problem is "nearest" sampling mode when drawing a BitmapData over a BitmapData. Perhaps the following might help:
var sh:Shape=new Shape();
sh.graphics.beginBitmapFill(bd,matrix,false,true);
sh.graphics.lineStyle(0,0,0); // no lines border this shape
sh.graphics.drawRect(0,0,resizedBD.width,resizedBD.height);
sh.graphics.endFill();
resizedBD.draw(sh); // or with smoothing on
Using Flash's native graphics renderer will most likely perform at least a bilinear interpolation on a drawn bitmap, which seemingly is your desired result. Also, stage.quality applies if that shape is added to stage (BTW, you can use the shape to display an uploaded pic, then draw over a BitmapData in order to save.) But, this might not work - I can't test this right now.

Resources