Some questions about color values during canvas.toDataURL conversion to RawTexture

At present, I am implementing to encode the height value into canvas and then pass it to RawTexture through toDataUrl method for use, but during this process, I found that Canvas.fillstyle can only accept standard CSS color values. How do I encode the position information with many decimal places correctly into the canvas? I think I might need an algorithm.

Some example code is as follows:

const canvas = document.createElement('canvas')
canvas.width = 8192
canvas.height = 8192
const ctx = canvas.getContext('2d')

const pickingInfo = scene.pick(x, y)
const center = pickingInfo.pickedPoint

cxt.fillStyle = `rgb(${center.y}, 0, 0)` // FIXME: Something needs to change here
cxt.arc(center.x, center.z, 10, 0, Math.PI * 2)

I have terrain information in my gltf and I want to modify the height of the topographical vertices by reading the colors in the RawTexture through the shader in the MaterialPlugin.

Any ideas from the guys?

Convert range 0 - 8192 data to range of the result - 255.

let colorChannel = Math.round(255 * (center.y / 8192));
cxt.fillStyle = `rgb(${colorChannel}, 0, 0)`;


You can also use hexadecimal with the “#” sign followed by RGB channel. Each channel take two characters space of 0 to F which make a total of 256 possibilities. In hexa, F = 16 and FF = 255.

This is for converting to hexadecimal:

hexa = number.toString(16);

I hope this help. :smiley:

1 Like

It’s a great idea, But will there be a loss of accuracy when performing inverse operations in shader?

vec4 _mix_terrain_texture_color = texture2D(
  _mix_terrain_texture,  // the raw texture object
float height = _mix_terrain_texture_color.r / 255 * 8192; // do this conversion here?
gl_Position= viewProjection * vec4(vPositionW.x, height, vPositionW.z, 1.0);

Whether there is a reversible algorithm or a method with a small error value?

I came up with a way to encode decimals, integers, and symbols separately into color channels.

const factor = 3000
const height = -123.1234567
const symbol = 100 or 0 // Store the sign bits separately, 100 if they are integers and 0 if they are negative
const r = rgba(255 * (123 / factor), symbol + 12, 34, 56)

in shader

vec4 _mix_terrain_texture_color = texture2D(
  _mix_terrain_texture,  // the raw texture object

float d1 = _mix_terrain_texture_color.r
if (d1 > 0) {
  float d2 = _mix_terrain_texture_color.g > 100 ? (_mix_terrain_texture_color.g - 100) * 0.01 : _mix_terrain_texture_color.g * 0.01
  float d3 = _mix_terrain_texture_color.b * 0.0001
  float d4 = _mix_terrain_texture_color.a * 0.00001
  float height = d1 + d2 + d3 + d4;
  float y = height / 255 * _mix_terrain_texture_color_factor
  gl_Position= viewProjection * vec4(vPositionW.x, y, vPositionW.z, 1.0);
Math.max(0, num);

For replacing negative with 0

Const num = -123.456;
const int = Math.max(0, num);

Should output 0 in the console when changing ‘num’ constant

I also found a problem why Canvas can’t change the rgba value to hexadecimal and transparent channels disappear. Do you know why?

You can’t draw transparency on a canvas I guess.

Change it’s CSS value ‘background’ or ‘background-color’ if you need to change the whole canvas color.

canvas.backgroundColor = "#00ff00";

CanvasRenderingContext2D.globalAlpha - Web API 接口参考 | MDN Use this property to set up a transparent channel

Oops sorry I forgot to add the alpha (transparency) channel at the end.
Here I use ‘80’ which if half ‘FF’ in hexadecimal.

const alpha = "80";
const color = "00FF00";
canvas.background = "#" + color + alpha;

Now I have another problem, this may require a new topic, when I use the same material plugin to operate on the ground material, changing some of the position offset parameters shows a different effect. Can someone help me figure this out?
You can swap comment lines to see the correct effect

1 Like