Simple3D FAQ

Frequently Asked Questions about Simple3D extension for TurboWarp.

Use your web browser's search feature (Ctrl+F) to search for what you need across this page.

General

Q: How to use Simple3D?
A: See example projects and block documentation.
Q: Why are there so many blocks?
A: Because there is no way to make a decent 3D extension without a lot of blocks. And because people who actually use this extension keep asking to add more. To start using the extension, you don't need to know most of them.
Q: Why is Simple3D called simple, even though it's not simple?
A: The word "Simple" primarily refers to what kind of graphics this extension is meant for. It's also relatively simple to use, especially when compared to raw WebGL. Simple to use doesn't mean simple to learn though.
Q: Are there youtube tutorials?
A: There are no official ones, but there are few unofficial ones.
Q: Why isn't Simple3D translated?
A: Due to the unusual way this extension is structured, the normal way it's done in other extensions wouldn't work. But it's planned.
Q: What other 3D extensions exist?
A: The most popular are:
  • Pen Plus (website, js) - Started as a simple expansion to pen extension, gradually evolved into having many features and shaders.
  • CST3D (js) - allows to switch sprites into 3D mode and treat sprites themselves as 3D models. Very easy to learn, but doesn't offer that much functionality.
  • Extra3D (js v1, js v2) - the most usable ThreeJS-based extension for TurboWarp

Features

Q: Does Simple3D support collision detection?
A: No, and it's never planned for multiple reasons:
  • Simple3D meshes are like scratch costumes, not like sprites. They don't have positions. And drawing them is comparable to stamping.
  • It is important to keep rendering extensions and collision extensions separate from each other to give people freedom to switch between rendering without changing collision or switch between collision without changing rendering. If something better than simple3D comes out for rendering, maybe you'll want to switch to that, but keep using the same collision code. Or if someone makes a better collision extension, you you'll want to use that, without bloating your project with simple3d collision, that you aren't even going to use.
  • To support this separation, Simple3D only stores vertex data and texture data in VRAM, not in normal RAM. Meanwhile collision requires storing another copy of the data in RAM. So regardless of how you choose to do collision, you wouldn't be wasting RAM storing 2 copies of the mesh.
Q: Does Simple3D support physics?
A: No. You should use a dedicated physics extension for that. For example, you can try using this.
Q: Does Simple3D support custom shaders?
A: No, and it's never planned, as it goes directly against the primary reasoning behind the extension's name - it's only meant for simple graphics. And as a result, the whole extensions was structured in accordance to expectation that shaders are never going to be added, so retroactively adding shaders to it now will result in suboptimal and messy set of blocks. Making a separate extension (Advanced3D) fully centered around shaders from the start is considered.
Q: Does Simple3D do any culling?
A: it only does backface culling, but only if it was manually enabled. Frustum culling and occlusion culling must be done by the project.
Q: Does Simple3D do frustum culling automatically?
A: No. Even though Simple3D has built-in blocks to make setting up projection transformations easier for most common cases, it really allows any custom projection. Because of that, only the projects knows the information necessary to do frustum culling, so it physically can't be added.
Q: Does Simple3D do occlusion culling automatically?
A: No. There exists a lot of approaches to occlusion culling, all with their own sets of pros and cons. None of them are universal, and they often require designing scene in some specific ways, like building map out of solid brushes with no holes and having it processed with BSP, manually placing occlusion portals, etc. Furthermore, it at the very least requires knowing what are all the objects in the scene, which Simple3D doesn't know. Simple3D just receives a stream of drawing commands from the project and executes them as they come. It can't predict what will come next. So it also cannot be added at all.
Q: How to do collisions?
A: Multiple options:
  • implement them yourself using math, lists and custom blocks
  • implement them yourself in 2D using touching blocks
  • use some other extension for collision or physics
Q: How to do lighting?
A: Simple3D wasn't designed for lighting, so either use some other 3D extension or implement inefficient workarounds, like shown in demo projects.
Q: How to use shaders?
A: Simple3D does not support shaders. However you can apply post processing effects to Simple3D layer using Pen Plus: Shaded extension by ObviousAlex.

Compatibility

Q: Does Simple3D work on PenguinMod?
A: Yes. Maintaining compatibility with PenguinMod is one of the goals. If you encounter any issues feel free to report bugs.
Q: Does Simple3D work in Snail IDE?
A: No, Snail IDE is based on a too outdated version of TurboWarp, that is missing important functionality that Simple3D relies of, like ability to add C-shaped blocks in extensions.
Q: Does Simple3D work in Gandi IDE?
A: No. There are broken unofficial ports, but do not contact Vadik1 about them.
Q: Will Simple3D ever get an official Gandi IDE version?
A: Maybe.
Q: Can Simple3D work in Scratch?
A: No.
Q: Does Simple3D support AR?
A: It doesn't do AR on its own. You need a separate extension for that. But it should be compatible with most other AR extensions.
Q: Does Simple3D support VR?
A: It doesn't do VR on its own. You need a separate extension for that. But it should be compatible with most other VR extensions.
Q: Is Simple3D only compatible with Vadik1's AR extension?
A: No, it should be compatible with most other AR extensions (if any exist). Simple3D and Vadik1's AR extension have a special integration to make passing matrices more convenient using less blocks, but the general-purpose way of passing matrices should still work with any other extension.
Q: What VR extensions Simple3D is compatible with?
A: It should be compatible with most other VR extensions. You can try Brackets-Coder's BlockifyVR extension.
Q: Why doesn't anisotropic filtering work for me?
A: Not all GPUs support it. If it's not supported, the blocks are programmed to simply do nothing, but you can still use those blocks to code projects for people who do have it supported.
Q: Why doesn't "compute color separately for each sample" work for me?
A: Not all GPUs support it. If it's not supported, the blocks are programmed to simply do nothing, but you can still use those blocks to code projects for people who do have it supported.
Q: Can projects with Simple3D be packaged?
A: Yes. Though if you are setting textures from costumes, you'll need to go into advanced settings of packager and turn off "Remove raw asset data after loading to save RAM". Note that changing that setting is also needed by most other extensions that read costumes.
Q: Can I use Simple3D and Pen Plus at the same time?
A: Yes, though they will draw to their own separate layers and wouldn't be able to interact with one another.
Q: Can I use Simple3D and Pen Plus at the same time to render into the same image?
A: No, Simple3D draws to it's own layer, and Pen Plus renders to pen layer. Pen Plus modifies TurboWarp's renderer, while Simple3D does all of its rendering on its own canvas with its own webgl2 context, and only copies the final rendered frame into the TurboWarp renderer. You can however use "Pen Plus Shaded" addon to apply basic post processing effects.
Q: How to pass depth buffer from Simple3D to Pen Plus or Shaded?
A: That's not possible and there isn't really a way to implement that in any performant way.
Q: Why isn't Video extension getting detected?
A: Immediately after importing, try switching between sprites to make block palette refresh. Also, you might be using an outdated version of the Video extension.

Textures

Q: What happens if I try to draw the mesh with texture coordinates, but without a texture?
A: The mesh will be drawn using Simple3D default texture.
Q: What does default texture look like?
A: a grey 2x2 checkerboard pattern with text consisting of: green TE in top left corner, red ST in top right corner, blue ST in bottom left corner, cyan TE in bottom right corner, resulting in tiled word TEST
Q: When does default texture show up?
A: Default texture shows up when the mesh has texture coordinates, but no texture.
Q: Can I set default texture to be blurred instead of pixelated?
A: No.
Q: Can I change default texture?
A: No.
Q: Why is image stretched?
A: If you are just drawing a quad from x:-1 y:-1 to x:1 y:1, then you'll need to adjust both for:
  • the aspect ratio of the stage (where x:-1 y:-1 is bottom left corner of the stage and x:1 y:1 is top right corner of the stage) (if you are using perspective or orthographic projection, they should take care of it automatically)
  • the aspect ratio of the image/texture `(mesh [mesh name] [texture width v])` and `(mesh [mesh name] [texture height v])`
Q: Why are textures upside down/vertically flipped?
A: This is not a quirk of Simple3D. For historic reasons, most things to work with 2D graphics and image formats have Y-axis facing down, meanwhile OpenGL/WebGL has Y-axis facing up. Due to this mismatch, things that have higher Y values that should end up lower, end up higher. WebGL has a built-in feature to flip images vertically when importing called gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); added specifically to mitigate this issue, but at this point Simple3D does not use it. However, it is planned.
Q: Can I make a mesh where different polygons use different textures?
A: no. Outside Simple3D, things that use multiple textures are usually drawn using multiple drawcalls, by first binding one texture and performing drawing, then binding another texture and drawing more. In Simple3D, each mesh is meant to represent exactly 1 draw call. So adding multiple textures like that is not planned. You can also have the definition of vertices the same for all sub-meshes, but use "draw vertex ranges" block to filter which range of vertices each sub-mesh draws. Alternatively, it's also common to combine multiple textures into one big texture called texture atlas, which allows to draw everything with one draw call. If you need multiple textures overlayed on top of one another, than that's different - that may actually be added. For now the solution is to draw multiple meshes on top of one another and set depth test to check if depth is "same", rather than "closer or same".
Q: How do I get texture atlases?
A: either make them manually or create code to generate them by rendering into texture.
Q: Can I make a section of a texture atlas repeat?
A: No. At least not yet.
Q: How to animate textures?
A: There are multiple ways:
  • upload each frame of animation into a separate mesh and then switch inheritance to switch between them.
  • put all frames of animation onto one texture atlas and animate by shifting UVs. There are blocks to change UV offset of a mesh or individual instance.
  • keep one texture, but render into it
Q: How do I not duplicate the same texture per mesh to save VRAM?
A: Create a mesh that has nothing but a texture, then use inheritance feature to inherit it by other meshes that need that texture.
Q: How to change texture format? (RGBA, RGB, RGBA32F, R32F)
A: All the textures are RGBA 8-bits per channel, and there is currently no way to change that.
Q: Why is texture rendered as black? Why not default texture?
A: It usually means the texture is still loading. Some types of texture sources are instant, but some require some time to load. Reading from costume requires 1 frame to load. So if you set texture and try to render within the same frame, it wouldn't work. It could also mean that the texture failed to load. You can use `(mesh [mesh name] [texture is loading])` block to check loading and `(mesh [mesh name] [texture has failed to load])` block to check if error happened.
Q: How to detect when texture finishes loading?
A: Use `(mesh [mesh name] [texture is loading])` block. `(mesh [mesh name] [texture has failed to load])` block may also be useful.
Q: Why is texture not setting?
A: Ensure that the texture providing block returns `[texture data]`, as well as use `(mesh [mesh name] [texture is loading])` and `(mesh [mesh name] [texture has failed to load])` to get more information.
Q: Why is texture not setting from URL?
A: While you can open any URL manually in the web browser fine and view it's content, by default websites can't access data from any other websites, unless those other websites explicitly grant permission to access data from them, which most websites don't do. This is called a CORS policy and you can read more about it here.
Q: Why did it load incorrect texture?
A: `[texture data]` is nothing more than a 15 character string. When you call a block that provides a texture, it does not return the texture as the value of a block itself, it puts it into a temporary variable within extension, while returning you `[texture data]` string. The texture accepting blocks just read from that internal variable. There can only be one at the time in that variable. So whichever texture providing block you called last, will be used by all subsequent texture accepting blocks. That is why storing texture data into variables for later or passing them through custom block arguments will often behave unexpectedly.
Q: How to solve texture seams when using texture atlas?
A: There are multiple reasons why texture seams may occur:
  • Antialiasing (MSAA) may be causing UV coordinates to be extrapolated out of bounds. In case of MSAA, pixel may only be partially covered by the triangle, with the center of the pixel not being covered. However, by default, the color is computed based on the center of the pixel.
    Solution: use `set [mesh name] compute color (once at midpoint of covered samples v)` for the mesh which has the problem or turn off antialiasing.
  • Lower resolution versions of textures from mipmapping may be combining adjacent areas into one pixel.
    Solution: turn off mipmapping.
  • When anisotropic filtering samples multiple points on the texture, it may be extrapolating UV out of bounds.
    Solution: turn off anisotropic filtering.
  • You may be using fractional values that cannot be represented precisely using finite amount of bits. Obviously don't use 1/3 ≈ 0.333333. But because computers work in binary, values like 1/10 also can't be represented exactly. Only powers of 2 (1/2, 1/4, 1/8, 1/16, ...) and their combinations (3/4, 7/16, 183/256, ...) can be represented accurately.
    Solution: ensure that your texture atlases are powers of 2.
Q: Why are vector textures pixelated?
A: GPUs only support bitmap textures. The way vector images are handled is by either converting them into bitmap once in advance, at a resolution high enough that pixelation isn't noticeable, or by converting vector image into polygonal 3D model, usually with some advanced shaders. Simple3D does not allow custom shaders, so this approach is quite limited. But you can still attempt to convert svg images into 3D models using Blender - for simple vector images that works quite well.
Q: How to change resolution at which vector images are rasterized?
A: There isn't currently a way, but it's planned.
Q: How do texture coordinates work?
A: Texture coordinates are denoted with letters U and V. U is X. V is Y. Both values range from 0 (bottom left corner) to 1 (top right corner) regardless of texture resolution or aspect ratio. However, when uploading images from external sources, the vertical axis gets flipped. So on costume or image loaded from URL, it ranges from 0 (top left) to 1 (bottom right).
Q: What happens when UV coordinates go out of 0 to 1 range?
A: What happens depends on what mode was set when texture was uploaded into the mesh:
  • "clamp to edge" means any values above 1 become 1, and any values below 0 become 0. That is, rows or columns of pixels at the edges of textures continue indefinitely.
  • "repeat" means that UV values are processed with `mod 1` operator. For example, 12.34 becomes 0.34. But -3.1 becomes 0.9.
Q: How to change different sides of default cube to have different textures?
A: == TODO ==
Q: Should I use cube textures for setting 6 sides of cube mesh to different textures?
A: No. Cube textures are mostly meant for effects that require transforming direction into color, like reflections, or cube projection. Using it for simple textured cubes is wasteful.
Q: What are cube textures for?
Cube textures are mostly meant for effects that require transforming direction into color, like reflections, or cube projection. Using it for simple textured cubes is wasteful.

Versions

Q: How to check my current Simple3D version?
A: Open browser devtools and look for a file named simple3D.js. For example, if extension outputs into the console with which flags it compiled shaders, you can click on the file on the right that printed it. Or you can try to find it in the Sources or Network tab. The version should be at the top of the file.
Q: How to change to a different version of Simple3D?
A: Go to changelog, find the js file of the version you want, download it or copy its content into the clipboard. Then open a new project in TurboWarp, first import the version of the extension you want to switch to, then import the project and then save the project. Since extension is already loaded, TurboWarp will not load the version of extension that the project used previously.
Q: Why is project not loading in TurboWarp desktop?
A: TurboWarp desktop may have an outdated version of the extension, compared to the version available on the web version, in which the project you are trying to open could've been made.
Q: Why is feature mentioned in the documentation is missing from the extension?
A: If you are using TurboWarp Desktop, your version of Simple3D might be outdated - check the website version. Documentation might also be referring to deprecated feature, the blocks for which were hidden.
Q: Does Simple3D have addon extensions that add more features to it?
A: Yes, you can find them here.
Q: Do I need to load Simple3D from file when using addons?
A: For some yes, for some no. Some addons hook into internals of Simple3D to apply their changes. With updates, Simple3D internals can change and are not guaranteed to stay compatible with addons, especially old versions of addons loaded from text that do not auto-update. So to keep it from breaking, the main extension should also be loaded in a way that prevents it from auto-updating.
Q: Where do I report a bug or write suggestions?
A: Either:
  • Vadik1's profile on Scratch
  • Xeltalliv's fork of turbowarp/extensions on github
  • The topic dedicated to Simple3D in #projects channel of TurboWarp discord server (best option, if you are already there)
Q: Where can I find the list of changes / changelog?
A: Here.
Q: You mentioned Simple3D originally used WebGL1. Where is that old unfinished discontinued version?
A: Here.

Graphics APIs

Q: Does Simple3D use WebGPU?
A: No.
Q: What graphics API does Simple3D use?
A: It uses WebGL2. It does not use WebGL1 or WebGPU.
Q: Can I use Simple3D without WebGL2?
A: No.
Q: Why Simple3D requires WebGL2 and not WebGL1?
A: Simple3D originally started with WebGL1, but it had too many issues unsolvable without switching to WebGL2, so it was changed:
  • In WebGL1, renderbuffers used for z-buffer can only use 16-bit precision which looks terrible compared to 24-bit precision of the main canvas. Ability to use 24-bit and 32-bit precisions for not just canvas were only added in WebGL2.
  • In WebGL1 vertex indices can only go up to 65535. In WebGL2 it's 4294967296. 65535 vertices per mesh is not a lot.
  • Instancing (one of the most used Simple3D features) is a WebGL2-only thing that cannot be polyfilled in any reasonably performant way. Drawing 1 million instances with 1 draw call can run at 60 fps. Polyfilling it with 1 million individual draw calls will be very slow.
  • In WebGL1, textures with sizes that are not power of 2 cannot repeat, have mipmaps, and use some other features. In WebGL2 those limitations were removed - textures can have any size and still use most features.
  • In WebGL1 skinning would only allow having up to 28 bones per mesh, while in WebGL2 - up to 60.
Q: Will you port it to WebGPU to make it faster?
A: Porting it to WebGPU will not make it magically faster. WebGPU is not faster on the GPU side. It doesn't allow drawing more polygons or make shaders faster. WebGPU only helps reduce CPU-side overhead, allowing people to do more draw calls. So if you are drawing a lot of polygons with one draw call, performance will be identical in both. TurboWarp already adds a lot of overhead to calling any extension blocks, so the overhead of actual draw calls is negligible compared to that. Simple3D still has a lot of room for optimization.
Q: Why is Simple3D so inefficient? Why does it recompute so much every time draw mesh is called? Why it's still written like it's WebGL1, not taking full advantage of WebGL2, despite requiring WebGL2?
A: It originally started as WebGL1-based extension. The goal was to release extension quickly, with many features missing, make prototyping on features quick and optimize later, once everything else is finalized.
Optimized version of Simple3D v1.1.0 does exist, but it is experimental and potentially has bugs. You can find it on Extensions page.
Q: Does Simple3D use a 3D graphics library like ThreeJS or BabylonJS?
A: No, it's custom-made.

Licensing

Q: What license does Simple3D use?
A: Most of the extension is licensed under Mozilla Public License Version 2.0 with the exception of m4 library from webglfundamentals.org, which is licensed under BSD 3 Clause license.
Q: Can I sell projects with Simple3D?
A: Sure! Read Mozilla Public License Version 2.0 and BSD 3 Clause licenses for more information.
But if you modify Simple3D within them, you must publish just your modified version of the extension separately as open source under the same license as original.
Q: Can I make my own extension based on Simple3D?
A: Sure, but you must keep any files you modified open source under the same license.
Also, to avoid inconveniencing Vadik1 by confused users, please make it clear that that version is yours, with your ideas (that Vadik1 may not neccessarily agree with) and maintained by you. How to do that the best is up to you.
Q: Can I port Simple3D to other mods?
A: Sure, but you must keep any files you modified open source under the same license.
Also, to avoid inconveniencing Vadik1 by confused users, please make it clear that that version is unofficial and maintained by you. How to do that the best is up to you.

Model importing

Q: How to extract mesh from importer into lists? (for example to use with Pen+)
A: Currently there isn't any way.
Q: Are single line obj files supported?
A: No, at least not yet.
Q: Is GLTF / GLB / FBX / DAE supported?
A: No, and it's not planned for Simple3D. GTLF / GLB are planned as a separate extension.
Q: Where to put mtl files?
A: You should put mtl files in the same list as obj file, but they must be before the obj data.
Q: How to import models with multiple textures?
A: Since each mesh by design can only have 1 texture, you'll need to split it into multiple meshes. For built-in obj importer a way to filter which polygons are imported based on texture is planned, but not yet supported. For now you'll need to separate obj file into multiple obj files by texture yourself, using external software or scratch script.
Q: Why are models not importing?
A: == TODO ==
Q: How to detect when mesh finished importing?
A: Wait until `(mesh [mesh name here] [has positions])` becomes true.
Q: How to import skinned mesh?
A: Currently the only supported file format is obj, which doesn't support it. You can code your own parser for other formats. Setting per vertex skinning weights and bone transformations is supported only from lists, so you may need to write your own parse for another file formats or generate meshes dynamically.
Q: How to import JSON?
A: You'll need to use a JSON extension for that.
Many things that people would like to do with JSON, can be done without JSON, and will run much faster. So nothing JSON related is added into Simple3D to discourage people from making slow code, and use JSON extension themselves where it's strictly necessary.
Q: How to import arrays? (lists as values)
A: Currently this is not supported. You'll need to turn them into normal scratch lists first.

Transformations

Q: How to use transformations?
A: == TODO ==
Q: How to do perspective projection?
A: == TODO ==
Q: How to do isometric projection?
A: == TODO ==
Q: What is "near" and "far" values in perspective projection?
A: The "near" and "far" values define the depth clipping boundaries. Any pixels with depth closer to the camera than the "near" value or further away than the "far" value will not rendered. Additionally, depth of each pixel in the depth buffer is stored as 24-bit number, which means there are only 16777216 possible values. The "near" and "far" define how depth will be mapped from its infinite range to that limited range. Setting "near" and "far" to closer values will result in higher precision and will make "Z-figting" issue less likely.
Q: Why is order in which pixels are drawn flickering?
A: That's likely an issue called "Z-fighting".
Q: How to reduce Z-fighting?
A: To reduce Z-fighting, try making "near" value of perspective projection higher or "far" value lower. If you need to render scene with high depth range, consider rendering everything in 2 passes: first for far range (e.g. 100, 10000), then clearing depth buffer and rendering same things again for close range (e.g. 0.1 to 100). Additionally, you may look into implementing "reverse Z".
Q: How to set position of a mesh?
A: Meshes are like costumes, and drawing them is like stamping. Meshes themselves don't have a position, but there are global transformations describing where any meshes will be drawn. For convenience and for some effects (like fog) to work correctly, global transformations are split into 3 steps: "to projected from view space", "to view space from world space", and "to world space from model space". For defining "position" of a mesh (as well as rotation and scale) you should configure "to world space from model space" transformation. The way to do this is usually to first scale and rotate the vertices of the mesh around its own origin, then move/offset/translate it to the correct position in the world. Since in code all the transformations are defined in the reverse order, it usually looks something like this:
					configure [to world space from model space v] transformation :: sensing
					start with no transformation :: sensing
					move X:(posX) Y:(posY) Z:(posZ) :: sensing
					rotate around [Y v] by (yaw) :: sensing
					rotate around [X v] by (pitch) :: sensing
					rotate around [Z v] by (roll) :: sensing
					scale X:(sizeX) Y:(sizeY) Z:(sizeZ) :: sensing
					
Q: How to set position of a camera?
A: Meshes are like costumes, and drawing them is like stamping. Meshes themselves don't have a position, but there are global transformations describing where any meshes will be drawn. For convenience and for some effects (like fog) to work correctly, global transformations are split into 3 steps: "to projected from view space", "to view space from world space", and "to world space from model space". For definiting position and rotation of the camera, you should configure "to view space from world space" transformation. The way to do this is usually to first offset all vertices from their world positions by the negative of the camera position, to move the entire world to move around the camera at 0,0,0, and then to rotate all vertices around 0,0,0 by the negative of camera look direction. Since in code all the transformations are defined in the reverse order, it usually looks something like this:
					configure [to view space from world space v] transformation :: sensing
					start with no transformation :: sensing
					rotate around [Z v] by ((0) - (camRoll)) :: sensing
					rotate around [X v] by ((0) - (camPitch)) :: sensing
					rotate around [Y v] by ((0) - (camYaw)) :: sensing
					move X:((0) - (camPosX)) Y:((0) - (camPosY)) Z:((0) - (camPosZ)) :: sensing
					
Q: What are transformations in Simple3D?
A: 4x4 matrices. They are referred to as "transformations" to make it sound less scary and prevent scratchers from giving up too early, but they are really just 4x4 matrices.
Q: What is wrapper block? Is wrapper block decorative?
A: It's not decorative. It saves the state of all transformations when you enter it and restores them back to that exact state when you exit. Keep in mind that when using this block not within "run without screen refresh" custom block, exiting it introduces a 1-frame delay because Scratch treats it internally as a loop.
Q: How to do first person item holding?
A: There are 2 ways to do it: the one where held item exists in the same world as all of your other 3d or in a separate world and is overlayed.
For the one where it exists "in the main world", you'll need to give it transformations such that it moves in the same way as the camera. You wouldn't need to modify "to view space from world space" transformation.
For the one where it exists "in a separate world", you'll need to::
  1. Set up "to view space from world space" transformation based on your main world camera position and rotation.
  2. Render all of your 3D scene.
  3. Set up "to view space from world space" transformation to be no transformation or some always the same transformation.
  4. Render your held item.

You can see example of the second approach here.
Q: How to render 2D UI?
A: Do it in the same way as first person item holding, but also modify "to projected from view space" transformation.
You can see example of it here.

Meshes

Q: What is inheritance?
A: Inheritance is a core feature that allows a mesh to reuse lists or properties from other meshes to prevent data duplication. You should use inheritance instead of uploading identical lists or textures into multiple meshes, as it saves memory.
Q: How to use mesh skinning?
A: == TODO ==
Q: Why is mesh not getting drawn?
A: == TODO ==
Q: Why is mesh rendered as black?
A: == TODO ==
Q: Why is mesh rendered as white?
A: == TODO ==
Q: How to change just 1 vertex?
A: == TODO ==
Q: How to change just 1 instance?
A: == TODO ==
Q: How to set everything from just 1 list?
A: Use:
					set [my mesh] interleaved [XYZ positions v] [your list v] :: sensing
					
Q: What does interleaved mean?
A: It means that instead of providing separate lists of X1 X2 X3 X4... Y1 Y2 Y3 Y4... Z1 Z2 Z3 Z4... you provide one list that has those values alternating: X1 Y1 Z1 X2 Y2 Z2 X3 Y3 Z3 X4...
Q: How to draw a sphere?
A: To draw a sphere you'll need a mesh of a sphere. Either generate it using code or import from obj. Generating it using code is not difficult, and if you are just learning simple3D, can be a nice exercise.
Q: How to draw a plane?
A: To draw a quad you'll need a mesh of a quad. Define it using lists or import from obj. Defining it using lists is preferred. One of the ways to do it:
Create 2 lists:
list xlist y
-1-1
-1 1
1-1
1 1
Upload them into a mesh, and set primitive type to "triangle strip", which will assemble 2 triangles from vertices 1,2,3 and 2,3,4.

Optimization

Q: How to make my project runs faster? Why is my project so laggy?
A: == TODO ==
Q: Why is my voxel game so laggy?
A: If you are drawing a mesh of a cube separately for each block, then that's why. There is no way to make that approach fast.
In order to create a voxel engine that is actually fast, you'll need to create code that generates a mesh for the entire world or the chunk of the world, while omitting any faces occluded by other solid blocks.
That will drastically reduce amount of draw calls (amount of times you call `draw mesh [mesh name]`).
Q: Should I use "overwrite color" blending when possible?
A: Yes. Proper blending requires reading previous color from VRAM. "overwrite" blending skips that step, improving memory throughput.
Q: What is overdraw?
A: == TODO ==
Q: Should I clear the screen if everything is going to be overdrawn anyways?
A: Yes! It provides an important clue for the GPU driver, which allows it to skip copying data of the previous frame.
Q: Should I start projects with "reset everything"?
A: You don't have to, but it's generally a good practice.
If you don't, you might accidentally depend on something, that you don't have the code to set up again, because you either did it manually, or removed, or broke the code that did it. In such case the project will appear to work, up until the next time you reopen the project and it's suddenly broken, because the thing it depended didn't get recreated. With "reset everything" you'll find and be able to fix all the problems like that immediately, rather than much later.
Q: Why did my project break if it worked fine yesterday? Why did my project break after reopening it?
A: Last time you used the project, you might've accidentally depended on something, that you don't have the code to set up again, because you either did it manually, or removed, or broke the code that did it. In such case the project will apper to work, up until the next time you reopen the project and it's suddenly broken, because the thing it depended didn't get recreated. If you don't use "reset everything" at the beginning of the project, the chances of this happening are much higher. It's also possible that Simple3D extension updated and introduced some bug. You can check for updates and load old version from this page. If Simple3D update broke it, please report the bug to Vadik1. It's also possible that TurboWarp updated, and your version of Simple3D became incompatible with it. When that happens, Simple3D might take some time to be updated. Additionlly, if you loaded Simple3D from text or file, you will need to update it manually (but that may break your addons).
Q: Can I toggle antialising without resetting everything?
A: No. This is a limitation of WebGL. Simple3D could've copied all the data from GPU back to RAM, recreated WebGL context and reuploaded all the data, but it would've added too much complexity to the code.
Q: What type of antialiasing Simple3D use?
A: MSAA. Same as WebGL. It doesn't require shaders and is implemented in hardware.

Render order

Q: Why are things rendered in the incorrect order?
A: == TODO ==
Q: Why when I'm rendering to texture, everything is incorrectly layered on top of one another?
A: Whether depth buffer is enabled and what comparison mode it is set to is stored for each render target separately. By default, depth writing is disabled. And memory for storing depth of pixels isn't even allocated until depth write is enabled. To better understand this, the following blocks may be useful: `(render target [has depth storage v])`, `(render target [depth write v])`, `(render target [depth test v])`, `(mesh [mesh name] [texture stores depth v])`, `(mesh [mesh name] [texture depth write v])`, `(mesh [mesh name] [texture depth test v])`.
Q: Why are transparent objects blocking other things from being drawn?
A: == TODO ==
Q: How to do transparency correctly?
A: First, draw all of your fully opaque objects (preferably in front to back order to avoid overdraw).
Then, switch depth writing off by using the "depth test (closer) write (off)" block, so that transparent items don't interfere with the depth buffer.
Finally, draw your transparent objects in back to front order.

Simple3D layer

Q: How do I do post processing effects?
A: You'll either need to:
  • figure out a way to do them using just the features Simple3D provides (like: rendering multiple copies of the image into itself with offsets to get blur or outlines, rendering with decreased brightness and then amplifying brightness to get visible color banding, etc.)
  • use shaded extension by ObviousAlex available on: https://pen-group.github.io/extensions/
Q: Does Simple3D draw on pen layer?
A: No, it draws on its own Simple3D layer, which is below the pen layer. Background - Video from camera layer - Simple3D layer - Pen layer - Sprite layer
Q: Can I reorder Simple3D layer? Can I draw Simple3D on top of sprites?
A: Yes. The best way is to hide the layer and assign one of the sprites to display the contents of Simple3D layer instead.
Alternatively you can use SharkPool's Layer Control extension from his gallery though that may cause some issues.
Q: How to make Simple3D layer not pixelated?
A: You can enable high quality pen to increase resolution. Or you can increase resolution using a dedicated block. Or you can switch interpolation from "pixelated" (aka "nearest") to "blurred" (aka "linear").

Fog

Q: Can I use multiple fogs at the same time?
A: No.
Q: Can I do depth-based fog instead of distance-based fog?
A: No, but this may be added in future updates.
Q: Can I do height fog?
A: No, but this may be added in future updates.

2D rendering

Q: Can Simple3D be used for 2D?
A: Yes. And in some cases it can even be faster than scratch's default ways to do 2D rendering. Especially in you need to render a lot of the same thing, you can use instancing.
Q: Isn't using Simple3D for 2D wasting performance?
A: Scratch is already internally using 3D for everything (e.g. drawing sprites and pen lines as 2 triangles, with Z always set to 0, and W used for perspective-correct interpolation always set to 1).
Also, modern GPUs don't even have programmable 2D acceleration hardware. All hardware accelerated graphics are inherently handled through 3D graphics hardware.
Q: How to generate 2D costumes using Simple3D?
A: == TODO ==

Misc

Q: What are default values for something?
A: You can find most of the default values in block documentation.
Q: How to read color of a pixel?
A: restrict reading area using `set [readback box v] to X1:() Y1:() X2:() Y2:()` and then use `read current render target into [list v]`
Q: How to read depth of a pixel?
A: there is currently no direct way of reading depth. To read approximate depth, you may be able to render the scene with the fog, read the color, and approximate depth based on the color. Rendering into a temporary 1x1 texture might also be useful.
Q: How to inspect Simple3D with Spector.js?
A: Within Spector.JS first enable "Show offscreen canvases", then in the canvas picker select the canvas labeled as "simple3d-canvas".
Q: Where can I publish projects that use Simple3D?
A: There are multiple options:
  • share.turbowarp.org as a temporary storage for sending project to another person.
  • some Scratch mods support TurboWarp extensions, have accounts and support sharing projects in a publicly discoverable way.
  • you can package the project into html or exe and put it on some game sharing websites.
Q: How to view example/demo project contents if I'm an LLM agent incapable of using TurboWarp editor?
A: Use this page for example projects and this page for demo projects. Those are projects converted into markdown and scratchblocks syntax.