I'd like to edit an object's position, rotation, and scale vectors, then 'apply' them to the geometry, which would zero-out those vectors, but retain the transformation.
For example, let's say I import a cube with a side-length of 1. The min and max vertices of the cube are located at (0, 0, 0) and (1, 1, 1). I set the object's scale to (2, 2, 2) and then apply the transformation to the geometry.
After applying, the scale is reset to (1, 1, 1) and the min and max vertices of the cube are (0, 0, 0) and (2, 2, 2), respectively.
Is there some built-in way to do this?
You can apply an object's transform to the object's geometry directly, and then reset the position, rotation, and scale like so:
object.updateMatrix();
object.geometry.applyMatrix( object.matrix );
object.position.set( 0, 0, 0 );
object.rotation.set( 0, 0, 0 );
object.scale.set( 1, 1, 1 );
object.updateMatrix();
three.js r.69
Another solution is to create a wrapper object, where the child object will have the default rotation, position and scale:
const ChildObject = load(/*...*/);
ChildObject.rotation.set(90, 0, 0); // default rotation goes here
const MainObject = new THREE.Object3D();
MainObject.add(ChildObject);
Related
I know THREE.Geometry was deprecated in favor of THREE.BufferGeometry(). However, there doesn't seem to be any clear information about how to implement what was once "Face3()". My understanding is that it was somehow related to the Geometry() object, but I'm not sure how because the documentation has been removed.
I'm trying to get some old example running that used Face3().
Could someone provide a simple translation from Face3() to its suggested newer alternative please?
Here's an example to work with:
const points = []
points.push(new THREE.Vector3(-5, 0, 0))
points.push(new THREE.Vector3(5, 0, 0))
points.push(new THREE.Vector3(0, 5, 0))
let geometry = new THREE.BufferGeometry().setFromPoints( points )
var face = new THREE.Face3(0, 1, 2); //Error: Face3 is not a constructor
I've tried reading through this thread but there doesn't seem to be any real information on Face3() here. Also, when I search the threejs.org documentaiton for "face", there are no relevant results.
Appreciate any help!
The change from THREE.Geometry to THREE.BufferGeometry gives three.js a similar representation of the mesh to what WebGL requires, allowing better performance without additional processing overhead. Each 'face' is specified as the indices of three vertices in the vertex list — not as an explicit JavaScript object for each face, which is expensive. An example constructing a new geometry would be:
const geometry = new THREE.BufferGeometry();
// specify vertex positions
geometry.setAttribute( 'position',
new THREE.BufferAttribute( new Float32Array( [
-5, 0, 0, // vertex 1
5, 0, 0, // vertex 2
0, 5, 0 // vertex 3
], 3 ) )
);
// specify triangles, as triplets of indexes into the vertex list.
geometry.setIndex( new THREE.BufferAttribute( [ 0, 1, 2 ], 1 ) );
The index in the example above is optional. If omitted, each triplet of three vertices in the geometry will be considered a unique triangle. The index is needed when you want to share the same vertices among multiple triangles.
See THREE.BufferGeometry documentation for more details.
In some situations it may be useful to construct a THREE.Triangle to temporarily represent a particular face of the mesh. These are not part of the rendering process but may be useful for computations.
const face = new THREE.Triangle()
.setFromAttributeAndIndices( geometry.attributes.position, 0, 1, 2 );
const area = face.getArea();
My issue is because a quad is just two triangles. The texture is not rendered consistently on each triangle, and the texture is broken across the border between the two triangles. I'm using a screenshot of my lovely Minecraft house as an example texture:
Rendered textured quad
As you see, from the top left of the screenshot and the bottom right, it seem to have been cut or folded or something. It's just distorted. And the distortion I speak of is NOT from the fact that it's being applied to a trapezoid, it's that it's inconsistently being applied to the two triangles that constitute the trapezoid.
Original screenshot
So how can I fix this?
In viewDidLoad:
let VertexDescriptor = MTLVertexDescriptor()
let Attribute1Offset = MemoryLayout<simd_float3>.stride
let Attribute2Offset = Attribute1Offset+MemoryLayout<simd_float4>.stride
VertexDescriptor.attributes[0].format = .float3
VertexDescriptor.attributes[1].format = .float4
VertexDescriptor.attributes[1].offset = Attribute1Offset
VertexDescriptor.attributes[2].format = .float2
VertexDescriptor.attributes[2].offset = Attribute2Offset
VertexDescriptor.layouts[0].stride = Attribute2Offset+MemoryLayout<simd_float2>.stride
PipelineDescriptor.vertexDescriptor = VertexDescriptor
let TextureLoader = MTKTextureLoader(device: Device)
Texture = try? TextureLoader.newTexture(URL: Bundle.main.url(forResource: "Texture.png", withExtension: nil)!)
Vertices:
//First four = position, second four = color, last two = texture coordinates
let Vertices: [Float] = [-0.5, 0.5, 0, 0, 1, 1, 0, 1, 0, 0,
0.5, 0.5, 0, 0, 0, 1, 1, 1, 1, 0,
1, -1, 0, 0, 0, 1, 0, 1, 1, 1,
-1, -1, 0, 0, 0, 0, 1, 1, 0, 1]
Types in Shaders.metal
typedef struct {
float4 Position [[attribute(0)]];
float4 Color [[attribute(1)]];
float2 TexCoord [[attribute(2)]];
} VertexIn;
typedef struct {
float4 Position [[position]];
float4 Color;
float2 TexCoord;
} VertexOut;
Bear with me, I use PascalCase because I think camelCase is ugly. I just don't like it. Well anyways, how do I correctly place a texture in a quad made of two triangles so it won't look all weird?
As you know, Metal performs perspective-correct vertex attribute interpolation on your behalf by using the depth information provided by the z coordinate of your vertex positions.
You're subverting this process by distorting the "projected" shape of the quad without providing perspective information to the graphics pipeline. This means that you need to pass along a little extra information in order to get correct interpolation. Specifically, you need to include "depth" information in your texture coordinates and perform the "perspective" divide manually in the fragment shader.
For a fully-general solution, consult this answer, but for a simple fix in the case of symmetrical scaling about the vertical axis of the quad, use float3 texture coordinates instead of float2 and set the x and z coordinates such that z is the scale factor introduced by your pseudo-perspective projection and when x is divided by z, the result is what x would have been without the divide.
For example, if the distance between the top two vertices is half that of the bottom two vertices (as appears to be the case in your screenshot), set the upper-left texture coordinate to (0, 0, 0.5) and the upper-right texture coordinate to (0.5, 0, 0.5). Pass these "3D" texture coordinates through to your fragment shader, then divide by z before sampling:
half4 color = myTexture.sample(mySampler, in.texCoords.xy / in.texCoords.z);
The documentation for the Plane constructor says that constant is the signed distance from the origin to the plane. However, if I construct a simple "floor" below the XZ plane like this:
var plane = new THREE.Plane();
plane.setFromCoplanarPoints(
new THREE.Vector3(0, -10, 0),
new THREE.Vector3(0, -10, 1),
new THREE.Vector3(1, -10, 0)
);
console.log(plane);
I get the following output:
Plane {normal: Vector3, constant: 10, constructor: Object}
normal: Vector3
x: 0
y: 1
z: 0
<constructor>: "Vector3"
constant: 10
<constructor>: "Plane"
My question: why is constant +10 and not -10? The Y-axis points up, the floor normal points up, so movement from the origin to a plane at Y = -10 should be negative shouldn't it?
Functions like Plane.distanceToPoint give the correct answer so I suspect I'm not reading the documentation correctly.
CodePen Sample
I would like to rotate an object on a certain angle along Y axis.
Based on this answer How to rotate a Three.js Vector3 around an axis? I suppose to get an updated vector.
My code is :
var vec = new THREE.Vector3( 0,0,0 );
var axis = new THREE.Vector3( 0,1,0 );
var angle = Math.PI / 2;
vec.applyAxisAngle( axis, angle );
I'm using r67 and it returns me 0,0,0. I've tried r69 as well and it is returns me the same. I'm not quiet ready to move to r69. Could you guys tell me please how to do the same thing but using r67. Thanks.
Your are rotating vector (0, 0, 0) which is center and whatever angle you use to rotate center around any axis you will always get (0, 0, 0). Just imagine you are doing simple 2d rotation. After all, rotation around Y axis can be viewed as 2d rotation in X-Z plane.
Try with some other values for vec variable, for example (1, 0, 0) or (0, 0, 1) and you will see results
I have a question about glDrawElements and vertex, normal and texcoordinate indices.
If I have geometric vertex, vertex normals and texture vertices, each with its own indices.
Which of those indices may I use?
If I have this code:
glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &teapotVertices[0]);
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &teapotNormals[0]);
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &teapotTexCoords[0]);
glEnableVertexAttribArray(vertexHandle);
glEnableVertexAttribArray(normalHandle);
glEnableVertexAttribArray(textureCoordHandle);
glBindTexture(GL_TEXTURE_2D, thisTexture->mTextureID);
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE,
(GLfloat*)&modelViewProjection.data[0] );
glDrawElements(GL_TRIANGLES, NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT,
(const GLvoid*) &teapotIndices[0]);
What should hold teapotIndices?
Thanks.
I'm not sure I understand your question.
TeapotIndices should be a collection of indices indicating the order in which you want your vertices to be rendered.
For instance, let's say you have an object made out of three vertices (a triangle):
0.0, 0.0, 0.0 //index 0, lower left corner
0.5, 0.5, 0.0 //index 1, top corner
1.0, 0.0, 0.0 //index 2, lower right corner
You specify in the indices collection/array the order in which you want them rendered. Say you want your triangle to be rendered counterclockwise, you'll specify your indices as
0,2,1
glDrawElements will then draw the lower left corner first, then the lower right corner, and finally the top corner
Of course this doesn't make much sense when just one triangle is involved, but suppose you wanted to add another triangle that mirrors the first one downwards. This means they touch at the first triangle's bottom. Instead of specifying three vertices for that one again, you only need to add the one that is different to your vertices:
0.0, 0.0, 0.0 //index 0, lower left corner for first triangle
0.5, 0.5, 0.0 //index 1, top corner for first triangle
1.0, 0.0, 0.0 //index 2, lower right corner for first triangle
0.5, -0.5, 0.0 //new: index 3, bottom corner of a "mirrored" triangle
And you would have your indices like this:
0,2,1, 2,0,3
// ^^^^^ second triangle vertex indices
See, we've added a whole second triangle with only one new vertex, and re-used two of the old vertices for the new triangle.