Exploring the world of Blazor web assembly, I embarked on a project to harness the power of JSInterop with Three.JS to draw lines. Following the guidelines provided in their tutorials available Here, I diligently installed Three.JS using npm and webpack, with a prebuild event neatly tucked away in my csproj file.
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="npm install" WorkingDirectory="NpmJS" />
<Exec Command="npm run build" WorkingDirectory="NpmJS" />
</Target>
Trouble arose when the canvas stubbornly appeared black, devoid of any creations, while the console warned me of numerous errors. Any guidance on troubleshooting this snag would be immensely appreciated. I understand that venturing into the realm of Three.js and webgl within Blazor is slightly uncharted territory. Here is the initial error that surfaced:
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)
Further investigations through the developer console revealed that THREE.BufferGeometry() was undefined, leading to the error when a method was called on an undefined object.
The code behind my Razor Page appeared as follows:
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");
}
}
}
}
Here's a snippet of 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 also included the following scripts in 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>
Additionally, I imported THREE in my NpmJS.src.index.js file like so:
import * as THREE from 'three';