I’ve created a blazor web assembly project and am trying to use the JSInterop to use Three.JS to draw a line, following their tutorial’s located Here. I’ve installed Three.JS using npm and webpack with a prebuild event in my csproj file.
<Target Name="PreBuild" BeforeTargets="PreBuildEvent"> <Exec Command="npm install" WorkingDirectory="NpmJS" /> <Exec Command="npm run build" WorkingDirectory="NpmJS" /> </Target>
The issue is that the canvas renders as black, with nothing else, while the console shows several errors. Any help debugging this would be greatly appreciated. I know I’m slightly in uncharted territory as using Three.js and webgl from blazor isn’t fully featured. Here is the first error:
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: (intermediate value).setFromPoints is not a function TypeError: (intermediate value).setFromPoints is not a function at Object.drawLine (https://localhost:44370/javascript/threeTutorial.js:21:53) at https://localhost:44370/_framework/blazor.webassembly.js:1:3942 at new Promise (<anonymous>) at Object.beginInvokeJSFromDotNet (https://localhost:44370/_framework/blazor.webassembly.js:1:3908) at Object.w [as invokeJSFromDotNet] (https://localhost:44370/_framework/blazor.webassembly.js:1:64232) at _mono_wasm_invoke_js_blazor (https://localhost:44370/_framework/dotnet.5.0.10.js:1:190800) at do_icall (<anonymous>:wasm-function[10596]:0x194e4e) at do_icall_wrapper (<anonymous>:wasm-function[3305]:0x79df9) at interp_exec_method (<anonymous>:wasm-function[2155]:0x44ad3) at interp_runtime_invoke (<anonymous>:wasm-function[7862]:0x12efff)
Debugging in the developer console shows that THREE.BufferGeometry() is undefined, and the error appears to be because of then trying to call the method on an undefined object.
My Razor Page code behind looks like this:
namespace MyProject.Shared.Components { /// <summary> /// The canvas for browser rendering using Webgl. /// </summary> public partial class GameCanvas : MyLayoutComponentBase { protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await JSRuntime.InvokeVoidAsync("threeTutorial.drawLine"); } } } }
My Javascript File:
window.threeTutorial = { drawLine: function () { const renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0)); renderer.setSize(window.innerWidth, window.innerHeight); document.getElementById("gameCanvas").appendChild(renderer.domElement); const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500); camera.position.set(0, 0, 100); camera.lookAt(0, 0, 0); const scene = new THREE.Scene(); //create a blue LineBasicMaterial const material = new THREE.LineBasicMaterial({ color: 0x0000ff }); const points = []; points.push(new THREE.Vector3(- 10, 0, 0)); points.push(new THREE.Vector3(0, 10, 0)); points.push(new THREE.Vector3(10, 0, 0)); const geometry = new THREE.BufferGeometry().setFromPoints(points); const line = new THREE.Line(geometry, material); scene.add(line); renderer.render(scene, camera); } }
I’ve also added the following scripts into my wwwroot.index.html page:
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script> <script src="javascript/threeTutorial.js"></script>
And am importing THREE in my NpmJS.src.index.js file here:
import * as THREE from 'three';
Advertisement
Answer
Prisoner 849’s comment was correct:
“Try newer (the latest) revision of three.js. IIRC, r79 has no implementation of .setFromPoints() for BufferGeometry”