DataTexture with LuminanceFormat UnsignedShort is not renderable - three.js

I've a small question concerning GL_LUMINANCE with uint16 data. I have some OpenGL code I want to bring to WebGL / three.js:
glTexImage2D(GL_TEXTURE_2D, 0, myColor, (ushort)width,
(ushort)height, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, imageData);
When running this basic sample code I get the error
texture bound to texture unit 0 is not renderable.
It maybe non-power-of-2 and have incompatible texture filtering.
I'm not an expert so maybe this does not work at all?
So thats the basic sample:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
<script type="text/javascript" src="js/three.js"></script>
</head>
<body>
<canvas id="c" width="800" height="800" style="border:1px solid">No canvas functionality</canvas>
<script>
var canvas = document.getElementById("c");
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, canvas.width / canvas.height, 0.1, 1000);
var renderer = new THREE.WebGLRenderer( { canvas: canvas } );
var test = new Uint16Array(2048 * 2048);
for(var i = 0; i < test.length; i++) {
test[i] = Math.floor((Math.random() * 0xFFFF) + 1);
}
var geometry = new THREE.PlaneGeometry(1, 1);
var tex = new THREE.DataTexture(test, 2048, 2048, THREE.LuminanceFormat, THREE.UnsignedShortType);
var material = new THREE.MeshBasicMaterial( { map: tex } );
var mesh = new THREE.Mesh(geometry, this.material);
material.map.needsUpdate = true;
scene.add(mesh);
var bbox = new THREE.BoundingBoxHelper( mesh, 0xFF0000 );
bbox.update();
scene.add( bbox );
camera.position.z = 1;
function render() {
renderer.render(scene, camera);
}
requestAnimationFrame(render);
</script>
</body>
</html>
Thanks in advance

After some digging on the net i found this forum entry:
There is no such thing as gl.SHORT or gl.UNSIGNED_SHORT for textures in OpenGL ES 2.0 nor WebGL
There is no such thing as gl.SHORT or gl.UNSIGNED_SHORT for textures
in OpenGL ES 2.0 nor WebGL
From the OpenGL ES 2.0 spec these are the only formats support
RGBA UNSIGNED_BYTE
RGB UNSIGNED_BYTE
RGBA UNSIGNED_SHORT_4_4_4_4
RGBA UNSIGNED_SHORT_5_5_5_1
RGB UNSIGNED_SHORT_5_6_5
LUMINANCE_ALPHA UNSIGNED_BYTE
LUMINANCE UNSIGNED_BYTE
ALPHA UNSIGNED_BYTE
OES_texture_float adds
RGBA FLOAT
RGB FLOAT
LUMINANCE_ALPHA FLOAT
LUMINANCE FLOAT
ALPHA FLOAT
So this solves it for me :)

Related

extrusion with threejs has wrong dimensions

I'm trying to understand how to extrude a path using threejs.
I looked at https://threejs.org/docs/index.html#api/en/geometries/ExtrudeGeometry
which is what I need.
Here is the code I tried:
// ------------------------------------------------
// BASIC SETUP
// ------------------------------------------------
// Create an empty scene
var scene = new THREE.Scene();
// Create a basic perspective camera
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 150;
// Create a renderer with Antialiasing
var renderer = new THREE.WebGLRenderer({antialias:true});
// Configure renderer clear color
renderer.setClearColor("#000000");
// Configure renderer size
renderer.setSize( window.innerWidth, window.innerHeight );
// Append Renderer to DOM
document.body.appendChild( renderer.domElement );
// ------------------------------------------------
// FUN STARTS HERE
// ------------------------------------------------
function make_graphics(){
// clean up:
for( var i = scene.children.length - 1; i >= 0; i--) {
obj = scene.children[i];
scene.remove(obj);
}
// Create a Shape Mesh with basic material
const shape = new THREE.Shape();
const x_len = 12;
const y_len = 8;
shape.moveTo( 0, 0 );
shape.lineTo( 0, y_len );
shape.lineTo( x_len, y_len );
shape.lineTo( x_len, 0 );
shape.lineTo( 0, 0 );
const extrudeSettings = {
steps: 2,
depth: 12,
bevelEnabled: true,
bevelThickness: 1,
bevelSize: 1,
bevelOffset: 0,
bevelSegments: 1
};
const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00, wireframe:true } );
const mesh = new THREE.Mesh( geometry, material ) ;
scene.add( mesh );
// Render Loop
var render = function () {
requestAnimationFrame( render );
mesh.rotation.x += 0.001;
mesh.rotation.y += 0.001;
// Render the scene
renderer.render(scene, camera);
};
render(1, 1, 1);
}
document.addEventListener("DOMContentLoaded", function(){
make_graphics();
});
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Three.js 101</title>
<!-- Simple reset to delete the margins -->
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
<!-- Three.js CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
</head>
<body>
<!-- Our code -->
<script src="script.js"></script>
</body>
</html>
The extrusion is very long. It should be 12 by 8 by 12 but you can see it looks like a long rod. Does anyone know why the dimensions look wrong?
You're using an old version of Three.js (r83). In that version, what became the depth option in ExtrudeGeometry was called amount, and it defaults to 100 if it's not present. If you change depth to amount in your extrudeSettings object, or (preferably) change your CDN link to import a more recent version of Three.js, your code should work as expected.

Is there a way to prevent culling a line when using an orthographic camera?

When using an orthographic camera I can't see the back side of my circle when it is angled.
It's as though the circle is being treated as a disc with a face that is blocking the view of where I expect to see the circle. Is there any way to use the orthographic camera but have not do any culling at all or at the very least not do any culling on this circle?
Do a rotate on this example to see what I'm saying:
// ------------------------------------------------
// BASIC SETUP
// ------------------------------------------------
// hard code canvas dimensions
const scale = 2;
const canvasHeight = 350 * scale;
const canvasWidth = 350 * scale;
// Create an empty scene
var scene = new THREE.Scene();
// Create a basic perspective camera
//var camera = new THREE.PerspectiveCamera( 75, canvasWidth/canvasHeight, 0.1, 1000 );
var camera = new THREE.OrthographicCamera( canvasWidth / - 2, canvasWidth / 2, canvasHeight / 2, canvasHeight / - 2, 1, 1000 );
camera.position.z = 4;
// Create a renderer with Antialiasing
var renderer = new THREE.WebGLRenderer({antialias:true});
// Configure renderer clear color
renderer.setClearColor("#C3C3C3");
// Configure renderer size
renderer.setSize(canvasWidth, canvasHeight);
// Append Renderer to DOM
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.update();
setTimeout(function() {
controls.reset();
}, 5000)
// ------------------------------------------------
// FUN STARTS HERE
// ------------------------------------------------
// Render Loop
var render = function () {
requestAnimationFrame( render );
//cube.rotation.x += 0.01;
//cube.rotation.y += 0.01;
controls.update();
// Render the scene
renderer.render(scene, camera);
// console.log(visibleWidthAtZDepth(camera,))
};
render();
function drawCircle()
{
let radius = canvasWidth / 2 - 5,
segments = 64,
material = new THREE.LineBasicMaterial( { color: 0x0000ff } ),
geometry = new THREE.CircleGeometry( radius, segments );
geometry.vertices.shift();
scene.add( new THREE.LineLoop( geometry, material ) );
}
drawCircle();
<!DOCTYPE html>
<html>
<head>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta charset="utf-8"/>
</head>
<body>
</body>
<style>
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.js"></script>
<script src="https://unpkg.com/three#0.85.0/examples/js/controls/OrbitControls.js"></script>
<script src="bolt-hole-calculator.js"></script>
</html>
Set your camera further away from the origin. You are encountering the circle intersecting the near plane, because the camera is only 4 units from the origin, and the circle radius is much larger than that.
// ------------------------------------------------
// BASIC SETUP
// ------------------------------------------------
// hard code canvas dimensions
const scale = 2;
const canvasHeight = 350 * scale;
const canvasWidth = 350 * scale;
// Create an empty scene
var scene = new THREE.Scene();
// Create a basic perspective camera
//var camera = new THREE.PerspectiveCamera( 75, canvasWidth/canvasHeight, 0.1, 1000 );
var camera = new THREE.OrthographicCamera(canvasWidth / -2, canvasWidth / 2, canvasHeight / 2, canvasHeight / -2, 1, 1000);
camera.position.z = 500;
// Create a renderer with Antialiasing
var renderer = new THREE.WebGLRenderer({
antialias: true
});
// Configure renderer clear color
renderer.setClearColor("#C3C3C3");
// Configure renderer size
renderer.setSize(canvasWidth, canvasHeight);
// Append Renderer to DOM
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.update();
setTimeout(function() {
controls.reset();
}, 5000)
// ------------------------------------------------
// FUN STARTS HERE
// ------------------------------------------------
// Render Loop
var render = function() {
requestAnimationFrame(render);
//cube.rotation.x += 0.01;
//cube.rotation.y += 0.01;
controls.update();
// Render the scene
renderer.render(scene, camera);
// console.log(visibleWidthAtZDepth(camera,))
};
render();
function drawCircle() {
let radius = canvasWidth / 2 - 5,
segments = 64,
material = new THREE.LineBasicMaterial({
color: 0x0000ff
}),
geometry = new THREE.CircleGeometry(radius, segments);
geometry.vertices.shift();
scene.add(new THREE.LineLoop(geometry, material));
}
drawCircle();
// Do a rotate on this example to see what I 'm saying:
<!DOCTYPE html>
<html>
<head>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta charset="utf-8" />
</head>
<body>
</body>
<style>
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.js"></script>
<script src="https://unpkg.com/three#0.85.0/examples/js/controls/OrbitControls.js"></script>
<script src="bolt-hole-calculator.js"></script>
</html>

Alpha color with ShaderMaterial

I am trying to write a shader material for displaying THREE.Points() objects with rounded points. I am doing this by controlling the alpha value in a fragment shader.
Below is a fully working version of my code. I am getting the desired effect of only colouring pixels within the circle. Outside, however, I am getting white instead of the background colour.
This question is related to mine. I tried setting material.transparent = true but it did not have any effect.
<html>
<head>
<title>THREEJS alpha shader</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
<script type="text/javascript" src="http://threejs.org/build/three.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
</head>
<body>
<!-- Shaders -->
<script type="x-shader/x-vertex" id="vertexshader">
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
gl_PointSize = 40.0; // pixels
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
varying vec4 color;
void main() {
// radius
float r = length(gl_PointCoord - vec2(0.5, 0.5));
if(r < 0.5) {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor = vec4(1.0, 1.0, 1.0, 0.0);
}
}
</script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var buffer = new Float32Array(3); // single point located at (0, 0, 0)
var geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(buffer,3) );
// create shader material
var material = new THREE.ShaderMaterial({
vertexShader : $('#vertexshader').text(),
fragmentShader : $('#fragmentshader').text(),
});
var point = new THREE.Points(geometry, material);
scene.add(point);
camera.position.z = 2;
var render = function () {
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
You need to enable alpha blending within the OpenGL context. I am not sure if there is a way to do this using three.js, but adding these GL commands to your render() function will suffice:
var render = function () {
var gl = renderer.context;
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
requestAnimationFrame( render );
renderer.render(scene, camera);
};
See the MDN docs on blendFunc for a bit more information on this.

three.js Particles closer to camera appears larger in Orthographic Camera

It seems that with OrthographicCamera, if a particle (Points) is closer to the camera it will just appear to be larger. While, for example, BoxGeometrys with same size will always be in the same size, regardless of their distances to the camera.
See the sample below, where the green & red cubes have the same size but different distances to camera, so do the two white particles:
var container, camera, controls, scene, renderer;
init();
animate();
function init() {
var container = document.getElementById('container');
camera =
new THREE.OrthographicCamera(-window.innerWidth / 2,
window.innerWidth / 2, -window.innerHeight / 2,
window.innerHeight / 2, 1, 400);
camera.position.z = 200;
controls = new THREE.OrthographicTrackballControls(camera);
controls.addEventListener('change', render);
scene = new THREE.Scene();
var light = new THREE.DirectionalLight()
light.position.set(1, 5, 10)
scene.add(light);
var light = new THREE.DirectionalLight(0xaaaaaa)
light.position.set(-10, -1, -5)
scene.add(light);
var light = new THREE.AmbientLight(0x555555)
scene.add(light);
var pGeo = new THREE.Geometry()
var pVec1 = new THREE.Vector3
var pVec2 = new THREE.Vector3
var a = 80
pGeo.vertices.push(pVec1.fromArray([-a, -a, -a]));
pGeo.vertices.push(pVec2.fromArray([a, a, a]));
scene.add(new THREE.Points(pGeo, new THREE.PointsMaterial({
size: 80
})))
var cGeo = new THREE.BoxGeometry(80, 80, 80);
var MPG1 = new THREE.MeshPhongMaterial({
color: 0xff0000
});
var cMesh1 = new THREE.Mesh(cGeo, MPG1);
cMesh1.position.set(a, -a, -a);
cMesh1.updateMatrix();
scene.add(cMesh1);
var MPG2 = new THREE.MeshPhongMaterial({
color: 0x00ff00
});
var cMesh2 = new THREE.Mesh(cGeo, MPG2);
cMesh2.position.set(-a, a, a);
cMesh2.updateMatrix();
scene.add(cMesh2);
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
renderer.render(scene, camera)
render()
}
function animate() {
requestAnimationFrame(animate);
controls.update();
}
function render() {
renderer.render(scene, camera);
}
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrthographicTrackballControls.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Particle_Orthographic</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>
<div id="container"></div>
</body>
</html>
I want to know, whether there is something I missed that can make particles behave in the same way as other Geometry with OrthographicCamera.
Because I am trying to visualise some aluminum matrix, OrthographicCamera is quite necessary to demonstrate the uniform crystal structure. Also the matrix would vary from 4^3 to 100^3 in volume (and number of aluminum atoms), so the scene will sort of keep changing size, and other Geometry will make it very slow.
Thanks in advance
When using THREE.PointsMaterial, to prevent the particle size from attenuating (changing size) with distance from the camera, set
material.sizeAttenuation = false;
three.js r.72

threejs : error when deleting a Geometry or BufferGeometry in combination with a Sprite/Ortho camera

I load some objects using the ctm binary loader in Threejs r69. This returns Mesh objects using a BufferGeometry internally.
I need to remove from the scene then delete one of these Meshes, including their material/texture/geometry. According to examples and google, I should use:
scene.remove(m_mesh);
m_mesh.geometry.dispose();
m_mesh.geometry = null;
m_mesh.material.dispose();
m_mesh.material = null;
m_mesh = null;
This removes the object from the scene, but the screen goes black for a second, and I've got a GL error :
Error: WebGL: drawElements: no VBO bound to enabled vertex attrib index 2!
Looks like the above sequence (ran in my render() operation, just before drawing the scene) did not clean everything, or at least I still have references to non existing VBOs somewhere.
I've spent quite some time debugging the problem and came to the conclusion that this happens only when using an orthographic camera with a Sprite and a Perspective camera, in 2 differents scenes.
Basically, I draw a flat background using a Sprite and a dedicated scene, then my 3D scene with Meshes. If I delete a mesh from the 3D scene, then the drawing of the flat background fails.
I can't figure out why. Looks like there's a side effect of deleting a Mesh on Sprites, even if attached to different scenes.
If I comment the background drawing, then the deletion of my mesh works perfectly.
I insert below a reproduction of the problem using the standard threejs distribution. Wait about 5 seconds and you should see some GL errors on the jaavscript console.
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - geometries</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="build/three.min.js"></script>
<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
if (!Detector.webgl) Detector.addGetWebGLMessage();
var container, stats;
var camera, scene, renderer;
frame_count = 0;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.y = 400;
// I need a second camera for my 2D sprite (used as a background)
// must use another texture so that it's not destroyed when removing the first object
cameraOrtho = new THREE.OrthographicCamera(window.innerWidth / -2,
window.innerWidth / 2,
window.innerHeight / 2,
window.innerHeight / -2,
1, 10);
cameraOrtho.position.z = 10;
cameraOrtho.position.y = 400;
sceneBackground = new THREE.Scene();
var map1 = THREE.ImageUtils.loadTexture('textures/disturb.jpg');
var material1 = new THREE.SpriteMaterial({
map: map1
});
var spriteBackground = new THREE.Sprite(material1);
spriteBackground.scale.set(window.innerWidth, window.innerHeight, 1);
spriteBackground.position.set(window.innerWidth / 2,
window.innerHeight / 2);
sceneBackground.add(spriteBackground);
scene = new THREE.Scene();
var light;
my_object = null;
scene.add(new THREE.AmbientLight(0x404040));
light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, 1, 0);
scene.add(light);
var map = THREE.ImageUtils.loadTexture('textures/UV_Grid_Sm.jpg');
map.wrapS = map.wrapT = THREE.RepeatWrapping;
map.anisotropy = 16;
var material = new THREE.MeshLambertMaterial({
map: map,
side: THREE.DoubleSide
});
// one object is enough to demonstrate
// can't reproduce the problem with a standard SphereGeometry
// try to convert it to a BufferGeometry
var sphereGeometry = new THREE.SphereGeometry(75, 20, 10);
var bufferGeometry = new THREE.BufferGeometry().fromGeometry(sphereGeometry);
my_object = new THREE.Mesh(bufferGeometry, material);
my_object.position.set(-400, 0, 200);
scene.add(my_object);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.autoClear = false;
renderer.autoClearDepth = false;
container.appendChild(renderer.domElement);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild(stats.domElement);
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//
function animate() {
requestAnimationFrame(animate);
render();
stats.update();
}
function render() {
frame_count++;
var timer = Date.now() * 0.0001;
camera.position.x = Math.cos(timer) * 800;
camera.position.z = Math.sin(timer) * 800;
camera.lookAt(scene.position);
//after a few frames I want to destroy completely the object
//means remove from the scene, remove texture, material, geometry
//note that here it's a Geometry, not a BufferGeometry
//may be different
if (frame_count > 60 * 5) {
if (my_object != null) {
console.log("destroy object buffer");
scene.remove(my_object);
my_object.material.map.dispose();
my_object.material.dispose();
my_object.geometry.dispose();
my_object = null;
}
}
for (var i = 0, l = scene.children.length; i < l; i++) {
var object = scene.children[i];
object.rotation.x = timer * 5;
object.rotation.y = timer * 2.5;
}
renderer.render(sceneBackground, cameraOrtho);
renderer.clearDepth();
renderer.render(scene, camera);
}
</script>
</body>
</html>
Any hints on how to fix this issue?
Thank you,
Pascal

Resources