Optix render animation

I want to add some animation to the objects, I tried to add transform node to the GeometryGroup, similar as Optix sample “optixDynamicGeometry”, the object did move, but it seems the shading and reflection are not correct, anyone knows why? Thanks!
result images are here:https://github.com/knightcrawler25/Optix-PathTracer/issues/5

optix::Aabb createGeometry(
	// output: this is a Group with two GeometryGroup children, for toggling visibility later
	optix::Group& top_group

	const std::string ptx_path = ptxPath("triangle_mesh.cu");

	top_group = context->createGroup();

	int num_triangles = 0;
	size_t i, j;
	optix::Aabb aabb;

		for (i = 0, j = 1; i < scene->mesh_names.size(); ++i, ++j) {

			GeometryGroup geometry_group = context->createGeometryGroup();

			OptiXMesh mesh;
			mesh.context = context;

			// override defaults
			mesh.intersection = context->createProgramFromPTXFile(ptx_path, "mesh_intersect_refine");
			mesh.bounds = context->createProgramFromPTXFile(ptx_path, "mesh_bounds");
			mesh.material = createMaterial(scene->materials[i], i);

			loadMesh(scene->mesh_names[i], mesh, scene->transforms[i]);

			Transform xform = context->createTransform();
			xform->setMatrix(false, Matrix4x4::identity().getData(), 0);

			aabb.include(mesh.bbox_min, mesh.bbox_max);

			std::cerr << scene->mesh_names[i] << ": " << mesh.num_triangles << std::endl;
			num_triangles += mesh.num_triangles;
		std::cerr << "Total triangle count: " << num_triangles << std::endl;
		GeometryGroup geometry_group = context->createGeometryGroup();

		for (i = 0; i < scene->lights.size(); ++i)
			GeometryInstance instance;
			if (scene->lights[i].lightType == QUAD)
				instance = createQuad(context, createLightMaterial(scene->lights[i], i), scene->lights[i].u, scene->lights[i].v, scene->lights[i].position, scene->lights[i].normal);
			else if (scene->lights[i].lightType == SPHERE)
				instance = createSphere(context, createLightMaterial(scene->lights[i], i), scene->lights[i].position, scene->lights[i].radius);
		//GeometryInstance instance = createSphere(context, createMaterial(materials[j], j), optix::make_float3(150, 80, 120), 80);


	return aabb;
void updateGeometry(optix::Group top_group)
	now_rotete += 3.1415926/3; now_position += make_float3(0.1, 0.1, 0.);
	for (unsigned int i = 0; i <scene->transformsNode.size(); i++) {
		//scene->transformsNode[i]->setMatrix(false, Matrix4x4::translate(now_position).getData(), 0);
		scene->transformsNode[i]->setMatrix(false, Matrix4x4::rotate(now_rotete, make_float3(0, 1, 0.)).getData(), 0);
	top_group->getContext()->launch(0, 0, 0);


Your quad and sphere lights are geometry objects inside the space ship and you didn’t transform them along with the other parts.

But the lights(two quads light under the top the ship) are outside of the ship. If so, I think it still ok if not transform them.

I meant the red screen inside the cockpit and the head light at the bottom front of the ship. Those are emissive geometries and should be handled as lights.
The image with the red hull looks like the light comes from the wrong direction and the floor in front of the headlight is missing the light cone on the floor visible in the correct image.

If that’s not it, you may have transformed the shading normals incorrectly if it works for identity and not for rotated transforms. That would also explain the opaque regions on the glass cockpit. But that cannot be seen in the given code excerpts.

Thank you Detlef, I check the code, but I still can’t find out the bug, the emissive geometric were include in the ‘scene->mesh_names’, so it seems already be transform, and the normals were included in the geometric buffer of ‘mesh.geom_instance’, code details of this are

loadMesh(scene->mesh_names[i], mesh, scene->transforms[i]);
void loadMesh(
    const std::string&          filename,
    OptiXMesh&                  optix_mesh, 
    const optix::Matrix4x4&     load_xform
  if( !optix_mesh.context )
    throw std::runtime_error( "OptiXMesh: loadMesh() requires valid OptiX context" );

  optix::Context context = optix_mesh.context;

  Mesh mesh;
  MeshLoader loader( filename );
  loader.scanMesh( mesh );

  MeshBuffers buffers;
  setupMeshLoaderInputs( context, buffers, mesh );

  loader.loadMesh( mesh, load_xform.getData() );

  translateMeshToOptiX( mesh, buffers, optix_mesh );

  unmap( buffers, mesh );
void translateMeshToOptiX(
    const Mesh&        mesh,
    const MeshBuffers& buffers,
    OptiXMesh&         optix_mesh
  optix::Context ctx       = optix_mesh.context;
  optix_mesh.bbox_min      = optix::make_float3( mesh.bbox_min );
  optix_mesh.bbox_max      = optix::make_float3( mesh.bbox_max );
  optix_mesh.num_triangles = mesh.num_triangles;

  std::vector<optix::Material> optix_materials;
  if( optix_mesh.material )
    // Rewrite all mat_indices to point to single override material
    memset( mesh.mat_indices, 0, mesh.num_triangles*sizeof(int32_t) );

    optix_materials.push_back( optix_mesh.material ); 
    bool have_textures = false;
    for( int32_t i = 0; i < mesh.num_materials; ++i )
      if( !mesh.mat_params[i].Kd_map.empty() ) 
        have_textures = true;

    optix::Program closest_hit = optix_mesh.closest_hit;
    optix::Program any_hit     = optix_mesh.any_hit;
    createMaterialPrograms( ctx, have_textures, closest_hit, any_hit );

    for( int32_t i = 0; i < mesh.num_materials; ++i )
      optix_materials.push_back( createOptiXMaterial(
            have_textures ) );

  optix::Geometry geometry = ctx->createGeometry();  
  geometry[ "vertex_buffer"   ]->setBuffer( buffers.positions ); 
  geometry[ "normal_buffer"   ]->setBuffer( buffers.normals); 
  geometry[ "texcoord_buffer" ]->setBuffer( buffers.texcoords ); 
  geometry[ "material_buffer" ]->setBuffer( buffers.mat_indices); 
  geometry[ "index_buffer"    ]->setBuffer( buffers.tri_indices); 
  geometry->setPrimitiveCount     ( mesh.num_triangles );
  geometry->setBoundingBoxProgram ( optix_mesh.bounds ?
                                    optix_mesh.bounds :
                                    createBoundingBoxProgram( ctx ) );
  geometry->setIntersectionProgram( optix_mesh.intersection ?
                                    optix_mesh.intersection :
                                    createIntersectionProgram( ctx ) );

  optix_mesh.geom_instance = ctx->createGeometryInstance(

} // namespace end

I transform the ship with 180 degrees, it seems the indirect lighting comes from before-transformed sense.

That is exactly what I was describing before.

Really, I have rendered that same exact scene in my own path tracer before and your error is possibly just some simple oversight, like a missing rtTransformNormal() or normalize() call inside the device code, or not updating the light definitions to contain proper transform matrices or transformed world coordinates to allow explicit sampling of the light geometry. None of that lighting related code is part of your posted code excerpts.

I would recommend to prune down the scene to the minimum failing case and then visualize the attributes on the surfaces to see if anything behaves not as expected or add some rtPrintf instructions to debug the lighting calculations on a failing pixel.

Maybe compare your code with the OptiX Introduction examples which implement a global illumination uni-directional path tracer with (or without) next event estimation for parallelogram lights and spherical environment lights with multiple importance sampling.
The simple scenes in those examples contain transforms over all individual objects as well and the closest hit programs, the light sample functions, and the miss shader for the environment light contain the necessary lighting calculations.

Links here: https://devtalk.nvidia.com/default/topic/998546/optix/optix-advanced-samples-on-github/

the bug solved, it is because when I am tring to do next even, I forget to convert the hit point to word space, fit this two line code, it works. Thank you Detlef!!

State state;
	[b]state.fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);;
	state.bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);[/b]
	state.normal = world_shading_normal;
	state.ffnormal = ffnormal;