New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using drei HTML is not showing anything #21
Comments
Hi, drei If you want to render text in VR I recommend using drei's |
Hi thanks for such a quick reply. Do you know how would I embed an image into the scene? |
Yeah for that you can place a Plane with an image texture |
You can also render textures dynamically by rendering HTML to a canvas using a library like html2canvas, then using that canvas as a texture on a plane. Here's an example of how to do that: import React from "react";
import html2canvas from "html2canvas";
import { renderToString } from "react-dom/server";
import * as THREE from "three";
import { useTexture } from "@react-three/drei";
import { useThree } from "@react-three/fiber";
// Prevents html2canvas warnings
// @todo maybe remove this if it causes performance issues?
HTMLCanvasElement.prototype.getContext = (function (origFn) {
return function (type, attribs) {
attribs = attribs || {};
attribs.preserveDrawingBuffer = true;
return origFn.call(this, type, attribs);
};
})(HTMLCanvasElement.prototype.getContext);
let container = document.querySelector("#htmlContainer");
if (!container) {
const node = document.createElement("div");
node.setAttribute("id", "htmlContainer");
node.style.position = "fixed";
node.style.opacity = "0";
node.style.pointerEvents = "none";
document.body.appendChild(node);
container = node;
}
export default function Html({
children,
width,
height,
color = "transparent",
}) {
const { camera, size: viewSize, gl } = useThree();
const sceneSize = React.useMemo(() => {
const cam = camera as THREE.PerspectiveCamera;
const fov = (cam.fov * Math.PI) / 180; // convert vertical fov to radians
const height = 2 * Math.tan(fov / 2) * 5; // visible height
const width = height * (viewSize.width / viewSize.height);
return { width, height };
}, [camera, viewSize]);
const lastUrl = React.useRef(null);
const [image, setImage] = React.useState(
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
);
const [textureSize, setTextureSize] = React.useState({ width, height });
const node = React.useMemo(() => {
const node = document.createElement("div");
node.innerHTML = renderToString(children);
return node;
}, [children]);
React.useEffect(() => {
container.appendChild(node);
html2canvas(node, { backgroundColor: color }).then((canvas) => {
setTextureSize({ width: canvas.width, height: canvas.height });
if (container.contains(node)) {
container.removeChild(node);
}
canvas.toBlob((blob) => {
if (blob === null) return;
if (lastUrl.current !== null) {
URL.revokeObjectURL(lastUrl.current);
}
const url = URL.createObjectURL(blob);
lastUrl.current = url;
setImage(url);
});
});
return () => {
if (!container) return;
if (container.contains(node)) {
container.removeChild(node);
}
};
}, [node, viewSize, sceneSize, color]);
const texture = useTexture(image);
const size = React.useMemo(() => {
const imageAspectW = texture.image.height / texture.image.width;
const imageAspectH = texture.image.width / texture.image.height;
const cam = camera as THREE.PerspectiveCamera;
const fov = (cam.fov * Math.PI) / 180; // convert vertical fov to radians
let h = 2 * Math.tan(fov / 2) * 5; // visible height
let w = h * imageAspectH;
if (width !== undefined) {
w = width;
}
if (height !== undefined) {
h = height;
}
if (height === undefined) {
h = width * imageAspectW;
}
if (width === undefined) {
w = h * imageAspectH;
}
return {
width: w,
height: h,
};
}, [texture, width, height, camera]);
React.useMemo(() => {
texture.matrixAutoUpdate = false;
const aspect = size.width / size.height;
const imageAspect = texture.image.width / texture.image.height;
texture.anisotropy = gl.capabilities.getMaxAnisotropy();
texture.minFilter = THREE.LinearFilter;
if (aspect < imageAspect) {
texture.matrix.setUvTransform(0, 0, 1, imageAspect / aspect, 0, 0.5, 0.5);
} else {
texture.matrix.setUvTransform(0, 0, aspect / imageAspect, 1, 0, 0.5, 0.5);
}
}, [texture, size, textureSize]);
return (
<mesh>
<planeBufferGeometry args={[size.width, size.height]} />
<meshBasicMaterial map={texture} side={THREE.DoubleSide} transparent />
</mesh>
);
} Then you can use it like the function App() {
return (
<Html width={2} height={2}>
<div
style={{
fontFamily: "Arial, sans-serif",
fontSize: "100px",
margin: "1px",
}}
>
<ol style={{ marginLeft: "1em" }}>
<li>
<strong>bold</strong>
</li>
<li>
<em>italics</em>
</li>
<li>
<span style={{ color: "red" }}>red</span>
</li>
<li>
<span style={{ color: "green" }}>green</span>
</li>
<li>
<span style={{ color: "blue" }}>blue</span>
</li>
</ol>
<img
src="/assets/test.png"
alt=""
crossOrigin="anonymous"
style={{ border: "0.1em solid red" }}
/>
</div>
</Html>
);
} |
Thanks @enijar . What if someone is using Next.js with r3f, here is a practice (FradSer/frad-me@3c17443) that hopefully helps. |
I have tried to add html when using react-xr. I am using HTML from drei but cannot get anything to show up.
The text was updated successfully, but these errors were encountered: