0
votes

My error pops up every time I try and render my scene in the animate() function. I am not sure what I have done wrong and am new to three.js.

$(function() {
  // var audioContext = new window.AudioContext();

  var ctx = new AudioContext();
  var audio = document.getElementById('TestAud');
  var audioSrc = ctx.createMediaElementSource(audio);
  var analyser = ctx.createAnalyser();

  audioSrc.connect(analyser);
  audioSrc.connect(ctx.destination);
  var frequencyData = new Uint8Array(analyser.frequencyBinCount);
  var scene, camera, renderer;
  var cube, cubeGeometry, cubeMaterial;
  var sphere, sphereGeo, SphereMaterial;

  function init() {
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    var renderer = new THREE.WebGLRenderer();

    renderer.setClearColor(0x000000);
    renderer.setSize(window.innerWidth, window.innerHeight);

    // var axis = new THREE.AxisHelper(10);
    // scene.add(axis);

    var cubeGeometry = new THREE.BoxGeometry(10, 6, 8);
    var cubeMaterial = new THREE.MeshBasicMaterial({
      color: 0x00FFFF,
      wireframe: true
    });
    var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

    var SphereGeo = new THREE.SphereGeometry(5, 8, frequencyData);
    var SphereMaterial = new THREE.MeshBasicMaterial({
      color: 0x00FFFF,
      wireframe: true
    });
    var sphere = new THREE.Mesh(SphereGeo, SphereMaterial);

    cube.position.x = 0;
    cube.position.y = 0;
    cube.position.z = 0;
    cube.name = frequencyData.length;

    sphere.position.x = 0;
    sphere.position.x = 0;
    sphere.position.z = 3;

    sphere.name = frequencyData.width;

    scene.add(cube);
    scene.add(sphere);

    camera.position.x = 40;
    camera.position.y = 40;
    camera.position.z = 40;
    camera.lookAt(scene.position);
    // renderer.render(scene, camera);

    $("#webGL-container").append(renderer.domElement);
  }

  function render() {
    analyser.getByteFrequencyData(frequencyData);
    // camera.updateProjectionMatrix();
  }

  function animate() {
    render();
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
  }

  $(window).resize(function(){
    SCREEN_WIDTH = window.innerWidth;
    SCREEN_HEIGHT = window.innerHeight;

    camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
    camera.updateProjectionMatrix();

    renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
  });

  init();
  animate();
  audio.play();
});
`

I appear to be getting this error,

Uncaught TypeError: Cannot read property ‘render’ of undefined

unless I put the code inside the init() function.

3

3 Answers

0
votes

Renderer is defined in init function so you can't use it in other function. So renderer is undefined, and udefined has no render property.

Don't declare renderer in init function, just use it.

function init(){
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    renderer = new THREE.WebGLRenderer();
    //...
0
votes

You create the renderer inside of the init function:

var renderer = new THREE.WebGLRenderer();

which makes the renderer local to the init function and is discarded as soon as the init function finishes.

Later on the animate function tries to use an undefined renderer:

renderer.render(scene, camera);

and that is where the exception occurs.

You should initialize the renderer this way:

renderer = new THREE.WebGLRenderer();

Please, notice the removed var keyword.

The same problem with camera and scene variables (and perhaps with a few more variables as well). You can solve the problem by using the "global" renderer variable (the one you declared out of the scope of the init function). Please, see the fixed code. Please, notice that the var keyword was removed from the renderer initialization in the init function - and the same for camera and scene.

$(function() {

//  var audioContext = new window.AudioContext();

  var ctx = new AudioContext();
  var audio = document.getElementById('TestAud');
  var audioSrc = ctx.createMediaElementSource(audio);
  var analyser = ctx.createAnalyser();

  audioSrc.connect(analyser);
  audioSrc.connect(ctx.destination);
   var frequencyData = new Uint8Array(analyser.frequencyBinCount);
   var scene, camera, renderer;
   var cube, cubeGeometry, cubeMaterial;
   var sphere, sphereGeo, SphereMaterial;


  function init(){
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  renderer = new THREE.WebGLRenderer();

  renderer.setClearColor(0x000000);
  renderer.setSize(window.innerWidth, window.innerHeight);

//  var axis = new THREE.AxisHelper(10);
  //scene.add(axis);

  var cubeGeometry = new THREE.BoxGeometry(10, 6, 8);
  var cubeMaterial = new THREE.MeshBasicMaterial({
    color: 0x00FFFF,
    wireframe: true
  });
  var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

  var SphereGeo = new THREE.SphereGeometry(5, 8, frequencyData);
  var SphereMaterial = new THREE.MeshBasicMaterial({
    color: 0x00FFFF,
    wireframe: true
  });
  var sphere = new THREE.Mesh(SphereGeo, SphereMaterial);

  cube.position.x = 0;
  cube.position.y = 0;
  cube.position.z = 0;
  cube.name = frequencyData.length;

  sphere.position.x = 0;
  sphere.position.x = 0;
  sphere.position.z = 3;


  sphere.name = frequencyData.width;

  scene.add(cube);
  scene.add(sphere);

  camera.position.x = 40;
  camera.position.y = 40;
  camera.position.z = 40;
  camera.lookAt(scene.position);
//  renderer.render(scene, camera);

    $("#webGL-container").append(renderer.domElement);
//
}

function render(){
  analyser.getByteFrequencyData(frequencyData);
//    camera.updateProjectionMatrix();
}

  function animate(){
    render();
    requestAnimationFrame(animate);
    renderer.render(scene, camera);

  }


  $(window).resize(function(){


      SCREEN_WIDTH = window.innerWidth;
      SCREEN_HEIGHT = window.innerHeight;

      camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
      camera.updateProjectionMatrix();

      renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );



  });

init();
animate();
audio.play();


});
-1
votes

As other answers are saying, you don't have access to the renderer variable outside of the scope of your init() function. Because of this, renderer is undefined in your animate() function, causing you to get an error.

Declare the variable outside the scope of init() in order to allow your other functions access to it. (You should do this with your scene and camera variables as well.)

// Declare the necessary variables outside of the scope of init()
var scene, camera, renderer;    

function init(){
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  renderer = new THREE.WebGLRenderer();
  ...
}

// animate() can now see the renderer var, since it's within the scope
function animate() {
  render();
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}