Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Standard Full Screen Quad Setup not Working in Three.js

I'm trying to establish a full screen quad using a pass thru vertex shader in THREE.js. The quad itself is a plane geometry with dimension (2, 2) located at the origin. It is assigned the ShaderMaterial. The camera is at z = 1 aiming at the quad.

The shaders are quite simple:

Vertex Shader:

void main() {
   gl_Position = vec4( position, 1.0 );
}

Fragment Shader:

void main() {
   gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}

But nothing shows up on screen. This setup is a standard way of render-to-texture, why is it not working in THREE.js?

I've tried plane.frustumCulled = false and changing the clip planes of the camera to no avail.

Any help is appreciated.


Upon further investigation, the reason for not seeing the rendering result is more involved and pointing to some odd behavior in three.js.

I am using a PlaneGeometry with a rotation matrix applied, which is then wrapped by an Object3D with a counter rotation.

var geometry = new THREE.PlaneGeometry(2, 2);
var m4 = new THREE.Matrix4().makeRotationX(Math.PI * 0.5);
geometry.applyMatrix(m4);

var mesh = new THREE.Mesh(geometry, material);
var obj = new THREE.Object3D();
obj.add(mesh);
obj.rotation.x = -Math.PI * 0.5;
scene.add(obj);

This setup seems to throw three.js off and no rendering is shown.


Ok, the rotation got thrown away because it is a part of model view matrix that I ignored in the vertex shader. I've to refact what I'm currently doing.

like image 327
user2566142 Avatar asked Sep 17 '25 11:09

user2566142


1 Answers

I'm not sure the exact problem you're having, but here is an example of a working fullscreen quad using the same technique.

var canvas = document.getElementById('canvas');
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true});
var camera = new THREE.PerspectiveCamera(45, canvas.clientWidth / canvas.clientWidth, 1, 1000);
var clock = new THREE.Clock();

var quad = new THREE.Mesh(
  new THREE.PlaneGeometry(2, 2),
  new THREE.ShaderMaterial({
    vertexShader: document.getElementById('vertex-shader').textContent,
    fragmentShader: document.getElementById('fragment-shader').textContent,
    depthWrite: false,
    depthTest: false
  })
);
scene.add(quad);

var box = new THREE.Mesh(
  new THREE.BoxGeometry(50, 50, 50),
  new THREE.MeshBasicMaterial({color: '#000', wireframe: true})
);
scene.add(box);

camera.position.z = 200;

render();

function render() {
  requestAnimationFrame(render);
  
  if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) {
    renderer.setSize(canvas.clientWidth, canvas.clientHeight, false);
    camera.aspect = canvas.clientWidth /  canvas.clientHeight;
    camera.updateProjectionMatrix();
  }
  
  var dt = clock.getDelta();
  box.rotation.x += dt * 2 * Math.PI / 5;
  box.rotation.y += dt * 2 * Math.PI / 7;
  box.rotation.z += dt * 2 * Math.PI / 11;
  
  renderer.render(scene, camera);
}
html, body, #canvas {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.min.js"></script>
<canvas id="canvas"></canvas>
<script id="vertex-shader" type="x-shader/x-vertex">
  varying vec2 vUv;

  void main() {
    vUv = uv;
    gl_Position = vec4(position, 1.0);
  }
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
  varying vec2 vUv;

  void main() {
    gl_FragColor = vec4(vUv, 0.0, 1.0);
  }
</script>
like image 171
Brendan Annable Avatar answered Sep 20 '25 03:09

Brendan Annable