I have custom shader where i have to send a segmentation id associated to each pixel in (x,y) position.
Now i am sending that as a texture and getting that data as:
float segID = sampleTexture(persTexture, vPosition.xy).r;
and the segmentation id is encoded as "r" in a texture but the problem here is that since the type is float32, if in any case i have segmentation id more than 255, i can't send that with texture because i can't put this data in texture.
Is there any way i can solve this?
can i have storage buffer or any hack to this?
var uniforms = {
// some other uniforms
persTexture: { type: 't', value: new THREE.Texture() },
//some other uniforms
}
and data is put as:
var imageData = new Uint8Array(4 * persDatas[threshold].length)
for (var x = 0; x < persDatas[threshold].length; x++) {
var segID = Math.floor((255 * persDatas[threshold][x]) / response.data.max)
imageData[x * 4] = segID
imageData[x * 4 + 1] = segID
imageData[x * 4 + 2] = segID
imageData[x * 4 + 3] = 255
}
var texture = new THREE.DataTexture(imageData, 4104, 1856)
texture.needsUpdate = true
persTextures[threshold] = texture
uniforms.persTexture.value = texture
can anyone help on this please??
Related
I am working on implementing Crytek's original SSAO implementation and I have found myself stuck and confused at the part where I need to find the view-space position of the sample. I have implemented a method which I feel should work however, it seems to give me an odd result with blackening occurring at the back. Am I missing something? Would appreciate any insight, thanks in advance.
vec3 depthToPositions(vec2 tc)
{
float depth = texture(depthMap, tc).x;
vec4 clipSpace = vec4(tc * 2.0 - 1.0, depth, 1.0);
vec4 viewSpace = inverse(camera.proj) * clipSpace;
return viewSpace.xyz / viewSpace.w;
}
for(int i = 0; i < ssao.sample_amount; ++i) {
// Mittring, 2007 "Finding next gen CryEngine 2" document suggests to reflect sample
vec3 samplePos = reflect(ssao.samples[i].xyz, plane);
samplePos.xy = samplePos.xy * 0.5 + 0.5; // conver to 0-1 texture coordinates
samplePos = depthToPositions(samplePos.xy); // this is how I am retrieving view-space position of sample
samplePos = viewSpacePositions + samplePos * radius;
vec4 offset = vec4(samplePos, 1.0);
offset = camera.proj * offset;
offset.xyz /= offset.w;
offset.xy = offset.xy * 0.5 + 0.5;
float sampleDepth = texture(gPosition, offset.xy).z;
float rangeCheck = (viewSpacePositions.z - sampleDepth) < radius ? 1.0 : 0.0;
occlusion += (sampleDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck;
}
Generating samples in C++
for(unsigned int i = 0; i < 64; i++) {
glm::vec4 sample(
randomFloats(generator) * 2.0 - 1.0,
randomFloats(generator) * 2.0 - 1.0,
randomFloats(generator) * 2.0 - 1.0, 0.0);
sample = glm::normalize(sample);
sample *= randomFloats(generator);
float scale = float(i) / 64;
scale = Lerp(0.1f, 1.0f, scale * scale);
sample *= scale;
ssaoKernel.push_back(sample);
}
I want to draw a fixed horizontal line (or a ruler) that gives info about size/distance or zooming factor like the one in Google Maps (see here).
Here is the another example with different zoom levels and camera used is orthographic
I try to implement the same with perspective camera but I would not able do it correctly
Below is the result I am getting with perspective camera
The logic that i am using to draw the ruler is
var rect = myCanvas.getBoundingClientRect();
var canvasWidth = rect.right - rect.left;
var canvasHeight = rect.bottom - rect.top;
var Canvas2D_ctx = myCanvas.getContext("2d");
// logic to calculate the rulerwidth
var distance = getDistance(camera.position, model.center);
canvasWidth > canvasHeight && (distance *= canvasWidth / canvasHeight);
var a = 1 / 3 * distance,
l = Math.log(a) / Math.LN10,
l = Math.pow(10, Math.floor(l)),
a = Math.floor(a / l) * l;
var rulerWidth = a / h;
var text = 1E5 <= a ? a.toExponential(3) : 1E3 <= a ? a.toFixed(0) : 100 <= a ? a.toFixed(1) : 10 <= a ? a.toFixed(2) : 1 <= a ? a.toFixed(3) : .01 <= a ? a.toFixed(4) : a.toExponential(3);
Canvas2D_ctx.lineCap = "round";
Canvas2D_ctx.textBaseline = "middle";
Canvas2D_ctx.textAlign = "start";
Canvas2D_ctx.font = "12px Sans-Serif";
Canvas2D_ctx.strokeStyle = 'rgba(255, 0, 0, 1)';
Canvas2D_ctx.lineWidth = 0;
var m = canvasWidth * 0.01;
var n = canvasHeight - 50;
Canvas2D_ctx.beginPath();
Canvas2D_ctx.moveTo(m, n);
n += 12;
Canvas2D_ctx.lineTo(m, n);
m += canvasWidth * rulerWidth;
Canvas2D_ctx.lineTo(m, n);
n -= 12;
Canvas2D_ctx.lineTo(m, n);
Canvas2D_ctx.stroke();
Canvas2D_ctx.fillStyle = 'rgba(255, 0, 0, 1)';
Canvas2D_ctx.fillText(text + " ( m )", (m) /2 , n + 6)
Can any one help me ( logic to calculate the ruler Width) in fixing this issue and to render the scale meter / ruler correctly for both perspective and orthographic camera.
Most of You interested in Raycasting probably know the Lodev and Permadi tutorials:
https://lodev.org/cgtutor/raycasting2.html
https://permadi.com/1996/05/ray-casting-tutorial-11/
At first I implemented so called "vertical floor/ceiling" raycast, it continues drawig column by column wall routine, it just starst drawing floors when the wall is done, that optimized thinking, but the algorithm itself is very, very slow.
So I tried Lodevs "horizontal floor/ceiling" raycast and it was huuuuge difference and speed up..
everything would be OK, but this algorithm, despite that is fast, wastes performance on filling up the
whole screen with floor and ceiling, and after that it draws walls.
I would like to optimize that feature, so the floor and ceiiling would be drawn after walls are drawn and fill only the empty spaces.
Maybe the solution would be to remember blank spaces during wall casting, and then create array containing that x, y coords, so during floor and ceil casting we already know where to draw.. what do you think. Do you know better aproaches, maybe some hints, learing sources, algorithms? Thanks in advance...
ps. I am using mouse to look around, so the horizon is changing.
I am developing on Windows but pararell I am porting my code to faster Amigas with m68k 060/080 cpus with RTG in 320x240x32 or 640x480x32.. I got nice results so far.. so trying to optimize az much as I can everything.
Below some of my tests, and progresses...
PC <-> AMIGA (WIN UAE)
https://www.youtube.com/watch?v=hcFBPfDYZig
AMIGA, V600 080/78 Mhz - 320x240x32 no textures (sorry for quality)
https://www.youtube.com/watch?v=6dv46hT1A_Y
Since the question is not related to any language, I answer from a Javascript perspective.
I implemented the so called "vertical floor/ceiling" technique as well.
But instead of drawing pixels per pixel with ctx.drawImage() I use putImageData.
First I get the data from the tiles I want to render using a temporary canvas:
var tempCanvas = document.createElement('canvas');
var tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = 64;
tempCanvas.height = 64;
var wallsSprite = new Image();
wallsSprite.onload = function () {
tempCtx.drawImage(wallsSprite, 0, 128, 64, 64, 0, 0, 64, 64);
floorData = tempCtx.getImageData(0, 0, 64, 64);
tempCtx.drawImage(wallsSprite, 0, 192, 64, 64, 0, 0, 64, 64);
ceilData = tempCtx.getImageData(0, 0, 64, 64);
}
wallsSprite.src = "./walls_2.png";
I create an empty imageData:
var floorSprite = this.ctx.createImageData(600, 400);
Then I do my "vertical floor/ceiling" raycasting:
//we check if the wall reaches the bottom of the canvas
// this.wallToBorder = (400 - wallHeight) / 2;
if (this.wallToBorder > 0) {
// we calculate how many pixels we have from bottom of wall to border of canvas
var pixelsToBottom = Math.floor(this.wallToBorder);
//we calculate the distance between the first pixel at the bottom of the wall and the player eyes (canvas.height / 2)
var pixelRowHeight = 200 - pixelsToBottom;
// then we loop through every pixels until we reach the border of the canvas
for (let i = pixelRowHeight; i < 200; i += 1) {
// we calculate the straight distance between the player and the pixel
var directDistFloor = (this.screenDist * 200) / (Math.floor(i));
// we calculate it's real world distance with the angle relative to the player
var realDistance = (directDistFloor / Math.cos(this.angleR));
// we calculate it's real world coordinates with the player angle
this.floorPointx = this.player.x + Math.cos(this.angle) * realDistance / (this.screenDist / 100);
this.floorPointy = this.player.y + Math.sin(this.angle) * realDistance / (this.screenDist / 100);
// we map the texture
var textY = Math.floor(this.floorPointx % 64);
var textX = Math.floor(this.floorPointy % 64);
// we modify floorSprite array:
if (floorData && ceilData) {
floorSprite.data[(this.index * 4) + (i + 200) * 4 * 600] = floorData.data[textY * 4 * 64 + textX * 4]
floorSprite.data[(this.index * 4) + (i + 200) * 4 * 600 + 1] = floorData.data[textY * 4 * 64 + textX * 4 + 1]
floorSprite.data[(this.index * 4) + (i + 200) * 4 * 600 + 2] = floorData.data[textY * 4 * 64 + textX * 4 + 2]
floorSprite.data[(this.index * 4) + (i + 200) * 4 * 600 + 3] = 255;
floorSprite.data[(this.index * 4) + (200 - i) * 4 * 600] = ceilData.data[textY * 4 * 64 + textX * 4]
floorSprite.data[(this.index * 4) + (200 - i) * 4 * 600 + 1] = ceilData.data[textY * 4 * 64 + textX * 4 + 1]
floorSprite.data[(this.index * 4) + (200 - i) * 4 * 600 + 2] = ceilData.data[textY * 4 * 64 + textX * 4 + 2]
floorSprite.data[(this.index * 4) + (200 - i) * 4 * 600 + 3] = 255;
}
}
}
}
}
finally we draw the floor and ceiling before the walls are rendered:
this.ctx.putImageData(floorSprite, 0, 0);
The result is super fast since:
we don't need to calculate ceiling texture coordinates since we deduce them from the floor coordinates.
we draw the ceiling/floor only once per loop, not pixels per pixel.
only the pixels that are visible are redrawn so it doesn't wastes performance on filling up the whole screen with floor and ceiling, and after that it draws walls.
Maybe it could be optimized with mixing horizontal raysting and putImageData put the game speed with wall/ceiling rendering or without is almost the same.
Here is the result
What I am doing now is, I am getting all pixels with var getPixels = require("get-pixels"), then I am looping over the array of pixels with this code:
var pixelation = 10;
var imageData = ctx.getImageData(0, 0, img.width, img.height);
var data = imageData.data;
for(var y = 0; y < sourceHeight; y += pixelation) {
for(var x = 0; x < sourceWidth; x += pixelation) {
var red = data[((sourceWidth * y) + x) * 4];
var green = data[((sourceWidth * y) + x) * 4 + 1];
var blue = data[((sourceWidth * y) + x) * 4 + 2];
//Assign
for(var n = 0; n < pixelation; n++) {
for(var m = 0; m < pixelation; m++) {
if(x + m < sourceWidth) {
data[((sourceWidth * (y + n)) + (x + m)) * 4] = red;
data[((sourceWidth * (y + n)) + (x + m)) * 4 + 1] = green;
data[((sourceWidth * (y + n)) + (x + m)) * 4 + 2] = blue;
}
}
}
}
}
The problem with this method is that the result image is too sharp.
What I am looking for is something, similar to this one which has been done with ImageMagick -sale
The command which I've used for the second one is
convert -normalize -scale 10% -scale 1000% base.jpg base2.jpg
the problem with this method is that I don't know how to specify the actual pixel size.
So is it possible to get the second result with that for loop. Or is better to use imagemagick -scale but if some one can help with the math, so I can have actual pixel size would be great.
Not sure what maths you are struggling with, but if we start with a 600x600 image like this:
Then, if you want the final image to have just 5 blocky pixels across and 5 blocky pixels down the page, you can scale it down to 5x5 and then scale it back up to its original size:
convert start.png -scale 5x5 -scale 600x600 result.png
Or, if you want to go to 10x10 blocky pixels:
convert start.png -scale 10x10 -scale 600x600 result2.png
The way you've written this, the image is processed into pixels of size nxn where n is specified by your pixelation variable. Increasing pixelation will provide the desired "coarseness".
Is there any built-in method in fabricjs that returns the coordinates of the starting point of a path ? I do not need the coordinates of the bounding rectangle.
Thanks!
To get the starting point you have to extract the point and calculate its actual position on canvas. As of fabric 1.6.0 you have all functions to do that, for the previous version you need a bit more logic:
example path:
var myPath = new fabric.Path('M 25 0 L 300 100 L 200 300 z');
point:
var x = myPath.path[0][1];
var y = myPath.path[0][2];
var point = {x: x, y: y};
Logic:
1) calculate path transformation matrix:
needs: path.getCenterPoint(); path.angle, path.scaleX, path.scaleY, path.skewX, path.skewY, path.flipX, path.flipY.
var degreesToradians = fabric.util.degreesToradians,
multiplyMatrices = fabric.util.multiplyTransformMatrices,
center = this.getCenterPoint(),
theta = degreesToRadians(path.angle),
cos = Math.cos(theta),
sin = Math.sin(theta),
translateMatrix = [1, 0, 0, 1, center.x, center.y],
rotateMatrix = [cos, sin, -sin, cos, 0, 0],
skewMatrixX = [1, 0, Math.tan(degreesToRadians(path.skewX)), 1],
skewMatrixY = [1, Math.tan(degreesToRadians(path.skewY)), 0, 1],
scaleX = path.scaleX * (apth.flipX ? -1 : 1),
scaleY = path.scaleY * (path.flipY ? -1 : 1),
scaleMatrix = [path.scaleX, 0, 0, path.scaleY],
matrix = path.group ? path.group.calcTransformMatrix() : [1, 0, 0, 1, 0, 0];
matrix = multiplyMatrices(matrix, translateMatrix);
matrix = multiplyMatrices(matrix, rotateMatrix);
matrix = multiplyMatrices(matrix, scaleMatrix);
matrix = multiplyMatrices(matrix , skewMatrixX);
matrix = multiplyMatrices(matrix , skewMatrixY);
// at this point you have the transform matrice.
Now take the rendering path process:
the canvas is transformed by matrix, then the point of path ar drawn with an offset that you can find in path.pathOffset.x and path.pathOffset.y.
So take your first point, subtract the offset.
point.x -= path.pathOffset.x;
point.y -= path.pathOffset.y;
Then
var finalpoint = fabric.util.transformPoint(point, matrix);
In new fabric 1.6.0 all the logic is in a function, you can just run:
var matrix = path.calcTransformMatrix(); and then proceed with transform Point logic.
Checkout the Path.path property. It is a 2D array containing an element for each path command. The second array holds the command in the first element e.g. 'M' for move, the following elements contain the coordinates.
var myPath = new fabric.Path('M 25 0 L 300 100 L 200 300 z');
var startX = myPath.path[0][1];
var startY = myPath.path[0][2];