Hi, after upgrading to the recent versions of Threejs, I figured out that (unlike, let’s say, MeshBasicMaterial
preserving colors specified by the color
parameter regardless of the render target) ShaderMaterial
produces the expected color only when rendered to screen. Here is an example:
<html>
<head><script src="three158.js"></script></head>
<body>
<canvas id="main" style="color: transparent; position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;"></canvas>
</body>
<script>
window.onload = function() {
var bg_clr = 0x0000c0,
cnv = document.createElement('canvas'), w = 100, h = 100,
rndr = new THREE.WebGLRenderer({ canvas: cnv }),
tgt = new THREE.WebGLRenderTarget(w, h, { depthBuffer: false, stencilBuffer: false, format: THREE.RGBAFormat }),
tex_data = new Uint8Array(w * h * 4),
tex = new THREE.DataTexture(tex_data, w, h, THREE.RGBAFormat, THREE.UnsignedByteType, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.LinearFilter, THREE.LinearFilter, 1),
scene = new THREE.Scene();
scene.add(new THREE.Mesh(new THREE.CircleGeometry(0.66, 4),
new THREE.MeshBasicMaterial({ color: 0x00c000 })));
scene.add(new THREE.Mesh(new THREE.CircleGeometry(0.33, 4),
new THREE.ShaderMaterial({ fragmentShader: 'void main() { gl_FragColor = vec4(0.75,0.0,0.0,1.0); }' })));
// Render to texture
rndr.setSize(cnv.width = w, cnv.height = h, false);
rndr.setRenderTarget(tgt);
rndr.setClearColor(bg_clr, 1);
rndr.clear();
rndr.render(scene, new THREE.OrthographicCamera(-1, 1, 1, -1, -1, 1));
rndr.readRenderTargetPixels(tgt, 0, 0, w, h, tex_data);
tex.needsUpdate = true;
var cnv2 = document.getElementById('main');
rndr2 = new THREE.WebGLRenderer({ canvas: cnv2 });
rndr2.setClearColor(bg_clr, 1);
rndr2.clear();
rndr2.setSize(cnv2.width, cnv2.height, false);
rndr2.render(new THREE.Mesh(new THREE.CircleGeometry(1, 4), new THREE.MeshBasicMaterial({ map: tex })), new THREE.OrthographicCamera(-1, 1, 1, -1, -1, 1));//render the texture
rndr2.render(scene, new THREE.OrthographicCamera(-1, 1, 1, -1, -1, 1));//or render the scene directly
};
</script>
</html>
Here are the results of rendering the scene with MeshBasicMaterial
(green) and ShaderMaterial
(red) directly (correct red color, #c00000
).
and rendering those two materials to a texture first before using it as a
map
for another MeshBasicMaterial
(lighter red color, #e00000
)How should that be tuned to get the red hardcoded in the fragment shader to be kept as is? In other words, how to properly mimic the MeshBasicMaterial
’s color conversions (or lack of) for all cases?